summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisplib.c2
-rw-r--r--share/txr/stdlib/op.tl21
-rw-r--r--txr.190
3 files changed, 107 insertions, 6 deletions
diff --git a/lisplib.c b/lisplib.c
index 8379abf9..1782e671 100644
--- a/lisplib.c
+++ b/lisplib.c
@@ -563,7 +563,7 @@ static val doloop_instantiate(val set_fun)
static val op_set_entries(val dlt, val fun)
{
val name[] = {
- lit("op"), lit("do"),
+ lit("op"), lit("do"), lit("lop"),
nil
};
set_dlt_entries(dlt, name, fun);
diff --git a/share/txr/stdlib/op.tl b/share/txr/stdlib/op.tl
index 78658658..e9ea8415 100644
--- a/share/txr/stdlib/op.tl
+++ b/share/txr/stdlib/op.tl
@@ -80,15 +80,26 @@
(syntax-0 (if (eq sym 'do) ^(,*args) ^[,*args]))
(syntax-1 (sys:op-alpha-rename f e syntax-0 nil))
(syntax-2 (sys:op-alpha-rename f e syntax-1 t))
- (have-metas (slot ctx 'gens))
+ (metas (slot ctx 'gens))
(rest-sym (sys:ensure-op-arg ctx 0)))
- ^(lambda (,*(cdr (slot ctx 'gens)) . ,rest-sym)
- ,(if (or have-metas (eq sym 'do))
- syntax-2
- (append syntax-2 rest-sym)))))
+ ^(lambda (,*(cdr metas) . ,rest-sym)
+ ,(let ((fargs (cdr (cdr syntax-2))))
+ (cond
+ ((and (eq sym 'lop) fargs)
+ (let ((fargs-l1 (mapcar (lambda (farg)
+ ^(sys:l1-val ,farg))
+ fargs)))
+ ^[sys:apply ,(car (cdr syntax-2))
+ (append ,rest-sym (list ,*fargs-l1))]))
+ ((or metas (eq sym 'do))
+ syntax-2)
+ (t (append syntax-2 rest-sym)))))))
(defmacro op (:form f :env e . args)
(sys:op-expand f e args))
(defmacro do (:form f :env e . args)
(sys:op-expand f e args))
+
+(defmacro lop (:form f :env e . args)
+ (sys:op-expand f e args))
diff --git a/txr.1 b/txr.1
index ec6e37c3..220259f8 100644
--- a/txr.1
+++ b/txr.1
@@ -40175,6 +40175,96 @@ from a quasiliteral within a nested
(mapcar (op list @2 @1) '((1 2) (a b))) -> ((2 1) (b a))
.cble
+.coNP Macro @ lop
+.synb
+.mets (lop << form +)
+.syne
+.desc
+The
+.code lop
+macro is variant of
+.code op
+with special semantics.
+
+The
+.meta form
+arguments support the same notation as those of the
+.code op
+operator.
+
+If only one
+.meta form
+is given then
+.code lop
+is equivalent to
+.codn op .
+
+If two or more
+.meta form
+arguments are present, then
+.code lop
+generates a variadic function which inserts all of its trailing
+arguments between the first and second
+.metn form -s.
+
+That is to say, trailing arguments coming into the anonymous function
+become the left arguments of the function or function-like object
+denoted by the first
+.meta form
+and the remaining
+.metn form -s
+give additional arguments. Hence the name
+.codn lop ,
+which stands for "left-inserting
+.codn op ".
+
+This left insertion of the trailing arguments takes place regardless of whether
+.code @rest
+occurs in any
+.metn form .
+
+The
+.meta form
+syntax determines the number of required arguments of the
+generated function, according to the highest-valued meta-number. The trailing
+arguments which are inserted into the left position are any arguments in excess
+of the required arguments.
+
+The
+.code lop
+macro's expansion can be understood via the following equivalences,
+except that in the real implementation, the symbols
+.code rest
+and
+.code arg1
+through
+.code arg3
+are replaced with hygienic, unique symbols.
+
+.cblk
+ (lop f) <--> (op f) <--> (lambda (. rest) [f . rest])
+
+ (lop f x y) <--> (lambda (. rest)
+ [apply f (append rest [list x y])])
+
+ (lop f x @3 y) <--> (lambda (arg1 arg2 arg3 . rest)
+ [apply f
+ (append rest
+ [list x arg3 y])])
+.cble
+
+.TP* Examples:
+
+.cblk
+ (mapcar (lop list 3) '(a b c)) --> ((a 3) (b 3) (c 3))
+
+ (mapcar (lop list @1) '(a b c)) --> ((a) (b) (c))
+
+ (mapcar (lop list @1) '(a b c) '(d e f))
+ --> ((d a) (e b) (f c))
+
+.cble
+
.coNP Macros @, ap @, ip @ ado and @ ido.
.synb
.mets (ap << form +)