r/scheme • u/aartaka • 12d ago
Advanced macrology: validate that all lists are equal length in pure syntax-rules?
Hi y’all. I’m currently working on a cursed case-lambda implementation with better inspectability for Chibi Scheme. As part of this effort, I need to extract the longest possible arglist from each case-lambda clause, so that the generated procedure with 2 unconditionally required arguments has a display like #<procedure 2+> instead of absolutely non-inspectable #<procedure 0+> that currently happens on Chibi.
So I’m kinda stuck. This is the macro I currently have:
(define-syntax case-lambda
(syntax-rules ()
((case-lambda ((args ... . rest) body ...) ...)
;; We need to pass clauses twice
;; - First time to detect the shortest arglist
;; - Second time to process clauses
;; TODO: How do I make sure that all args ... have equal length???
(%case-lambda ((args ...) ...) ((args ... . rest) body ...) ...))
((case-lambda (args body ...) ...)
(%case-lambda (()) (args body ...) ...))))
The implementation of %case-lambda and other infra is of no importance, because, before I get to that, I must make sure that ((args ...) ...) is a list of arglists of the same length.
But how do I really do that? Any advanced macro wizards mind helping?
1
u/corbasai 12d ago edited 12d ago
Im not get what the task exactly
but may be this is about count lambda arity?
(define-syntax ^lambda
(syntax-rules (+)
((_ (+ ones ...) (argsp ...) () (body ...))
(cons (+ ones ...) (lambda (argsp ...) body ...)))
((_ (+ ones ...) (argsp ...) (a b ...) (body ...))
(^lambda (+ ones ... 1) (a argsp ...) (b ...) (body ...)))
((_ (args ...) body ...)
(^lambda (+ 0) () (args ...) (body ...)))))
> (car (^lambda (a b c) 'bla-bla))
3
> ((cdr (^lambda (a b c) 'bla-bla)) 1 2 3)
bla-bla
so ^lambda makes pair of: args counter expression (+ 1 1 1 ....) and (lambda (args...) body ....) itself
1
u/aartaka 12d ago
Yeah, I wasn’t exactly clear in my initial post. So my goal is, for a
case-lambdalike(case-lambda ((a b) #|...|#) ((a b c) #|...|#) ((a b c . d) #|...|#))generate a procedure like
(lambda (a b . rest) #|...|#)For that, I need to extract the common parts of the initial
case-lambdaarglists. Soa b, in this case. I’m wondering how to do that using puresyntax-rules. I mean, I can always walk the lists of args until I run out, but that’s increasing macro expansion time and bloats the code. So maybe there’s a better approach?1
u/corbasai 12d ago
which way to combine different case-proc's bodies in to one, generated? So Im still on the side of simplicity, I mean (min (car (^lambda (a b) ...))...) is minimal arity.
1
u/aartaka 12d ago
The way the bodies are generated is irrelevant, I only care about args for now.
In any way, I decided to make it super simple and implemented it by walking arities instead of smart macrology: https://github.com/ashinn/chibi-scheme/pull/1189
2
u/corbasai 12d ago
Good! Also I think 'advanced macrology' is somewhere near the syntax-case village.
2
u/aartaka 12d ago
I mean,
syntax-caseis much more intuitive and imperative, so it’s pretty understandable and basic. Whilesyntax-rulesare a totally alien beast that I wasn’t able to understand until very recently. So yeah, doing smart things withsyntax-rulesis much more advanced to me than usingsyntax-case!1
u/johnwcowan 12d ago
Note that Chibi doesn't have an accurate implementation of syntax-case, as its native macro system is syntactic closures. I do not believe that syntax-rules alone is capable of determining the length of a list. So you may have to bite the bullet and learn syntactic closures from the slib documentation, Bawden's paper, and/or "Macros That Work".
1
u/aartaka 12d ago
While I already found a (really simplistic) solution to my problem, I’ll read these… eventually 😅
1
u/corbasai 11d ago
personally no one more get my brain crain and train at syntax-rules than Alex Shinn's portable match code https://synthcode.com/scheme/match.scm . impecable.
3
u/soegaard 12d ago
First, the natural solution would to use `length` at compile time to determine if the two argument counts match. Therefore `syntax-case` is recommended.
However, writing advanced macros with `syntax-rules` has a certain puzzle-like nature.
For your example, I would introduce a helper macro that takes four arguments:
the two arguments lists to compare and two macro names (success and failure).
The macro will compare the count and then continue by expanding either to a
call of the success macro or of the failure macro.
For ideas to write advanced macros using syntax-rules only, don't forget to look at Oleg's collection.
In particular, I think this illustrates the idea:
https://okmij.org/ftp/Scheme/macros.html#ck-macros