| After writing some code which looked like: (if (no (expr1))
(...)
I was thinking "there must be a macro already like 'ifn' which would take out the extra (no ...)". Unless works sort of like this but it's more like "when" than "if".Unless doesn't work for the following, what if I wanted the equivalent of: (if (no (expr))
(...then...)
(...else...))
That's not supported.Also if I wanted multiple (if (nos)) like: (if (no (expr1))
(...)
(no (expr2))
(...))
The code to write a "ifn" macro is so similar to aif: (mac ifn0 (expr . body)
`(if (no ,expr)
,@(if (cddr body)
`(,(car body) (ifn0 ,@(cdr body)))
body)))
Here's the current aif: (mac aif (expr . body)
`(let it ,expr
(if it
,@(if (cddr body)
`(,(car body) (aif ,@(cdr body)))
body))))
They are very similar - so much so it's a smell. The only difference is that, one applies the "no" function, one captures the "it" variable, and then when recursing they call different macros.So here's a more generic if macro which pulls out the similarities: (mac genif (sym f expr . body)
`(let ,sym (,f ,expr)
(if ,sym
,@(if (cddr body)
`(,(car body) (genif ,sym ,f ,@(cdr body)))
body))))
Now we can express both aif and ifn like: (mac ifn (expr . body)
`(genif ,(uniq) no ,expr ,@body))
(mac aif (expr . body)
`(genif it idfn ,expr ,@body))
; create a new macro mixing the two above
(mac aifn (expr . body)
`(genif it no ,expr ,@body))
As a bonus - I believe iflet can be re-written using genif. I'm not sure because I don't see how to test it but based on what the code is doing the following is more or less equivalent: (mac iflet (var expr then . rest)
`(genif ,var idfn ,expr ,@(cons then rest)))
This is not 100% equivalent because genif will make the captured var available in both the "then" and "else" clauses. It will also reset the value of var on subsequent "else-if" clauses. The arc1 iflet doesn't appear to do either of those which I'd argue are bugs because they are inconsistent with aif. |