9 Combiners
There are two types of combiners in Kernel, operative and applicative. Both types are encapsulated. All combiners are immutable. Two applicatives are eq?
iff their underlying combiners are eq?
. However, eq?
-ness of operatives is only constrained by the general rules for eq?
, which leave considerable leeway for variation between implementations. klisp only considers eq?
those operatives constructed by the same call to a constructor (e.g. $vau
). Two combiners are equal?
iff they are eq?
.
The primitive type predicate for type operative.
operative?
returns true iff all the objects inobjects
are of type operative.
The primitive type predicate for type applicative.
applicative?
returns true iff all the objects inobjects
are of type applicative.
<formals>
should be a formal parameter tree;<eformal>
should be either a symbol or#ignore
. If<formals>
does not have the correct form for a formal parameter tree, or if<eformal>
is a symbol that also occurs in<formals>
, an error is signaled.A
vau
expression evaluates to an operative; an operative created in this way is said to be compound. The environment in which thevau
expression was evaluated is remembered as part of the compound operative, called the compound operative’s static environment.<formals>
and<objects>
are copied as bycopy-es-immutable
and the copies are stored as part of the operative being constructed. This avoids problem if these structures are later mutated.When the compound operative created by
$vau
is later called with an object and an environment, here called respectively the operand tree and the dynamic environment, the following happens:
- A new, initially empty environment is created, with the static environment as its parent. This will be called the local environment.
- A stored copy of the formal parameter tree formals is matched in the local environment to the operand tree, locally binding the symbols of formals to the corresponding parts of the operand tree. eformal is matched to the dynamic environment; that is, if eformal is a symbol then that symbol is bound in the local environment to the dynamic environment.
- A stored copy of the expressions is evaluated sequentially from left to right, with the last (if any) evaluated as a tail context, or if the list of expressions is empty, the result is inert.
NOTE: Because compound operatives are not a distinct type in Kernel, they are covered by the encapsulation of type operative. In particular, an implementation of Kernel cannot provide a feature that supports extracting the static environment of any given compound operative, nor that supports determining whether or not a given operative is compound.
The
wrap
applicative returns an applicative whose underlying combiner iscombiner
.
The
unwrap
applicative returns the underlying combiner ofapplicative
.
<formals>
should be a formal parameter tree.The
$lambda
operative is defined by the following equivalence:($lambda formals . objects) == (wrap ($vau formals #ignore . objects))
Applicative
apply
combines the underlying combiner ofapplicative
withobject
in a tail context with dynamic environmentenvironment
(if the long form is used) or in an empty environment (if the short form is used).The following equivalences hold:
(apply applicative object environment) == (eval (cons (unwrap applicative) object) environment) (apply applicative object) == (apply applicative object (make-environment))
lists
must be a nonempty list of lists; if there are two or more, they must all have the same length. Iflists
is empty, or if all of its elements are not lists of the same length, an error is signaled.The
map
applicative appliesapplicative
element-wise to the elements of the lists inlists
(i.e., applies it to a list of the first elements of thelists
, to a list of the second elements of thelists
, etc.), using the dynamic environment from whichmap
was called, and returns a list of the results, in order. The applications may be performed in any order, as long as their results occur in the resultant list in the order of their arguments in the originallists
. Iflists
is a cyclic list, each argument list to whichapplicative
is applied is structurally isomorphic tolists
. If any of the elements oflists
is a cyclic list, they all must be, or they wouldn’t all have the same length. Leta1...an
be their acyclic prefix lengths, andc1...cn
be their cycle lengths. The acyclic prefix lengtha
of the resultant list will be the maximum of theak
, while the cycle lengthc
of the resultant list will be the least common multiple of theck
. In the construction of the result, applicative is called exactlya + c
times.
— Applicative: vector-map (vector-map applicative . vectors)
— Applicative: bytevector-map (bytevector-map applicative . bytevectors)
strings
,vectors
, orbytevectors
should be non-empty lists of the corresponding type and all elements should be of the same length.These applicatives behave as
map
except that the list of elements passed toapplicative
are the n-th chars, objects, or uint8s of the strings, vectors or bytevectors passed as arguments.SOURCE NOTE: These are taken from r7rs.