Arc Forumnew | comments | leaders | submitlogin
rif
5 points by evanrmurphy 2691 days ago | 5 comments
iflet only binds its var to the first expr if it's true. This macro, like aif, will bind to whichever expr happens to be true:

  (mac rif (var expr . body)
    `(let ,var ,expr
       (if ,var
           ,@(if (cddr body)
                 `(,(car body) (rif ,var ,@(cdr body)))
                 body))))
Since it's a more general aif, you can consolidate code by redefining aif in terms of rif:

  (mac aif (expr . body)
    `(rif it ,expr ,@body))
The name was inspired by rfn, which is to afn as rif is to aif.


4 points by fallintothis 2689 days ago | link

Bug report: aif knows there will be no destructuring in the variable (its variable is it), so it needn't worry whether the variable is actually an expression in certain contexts. But if you pass a destructuring expression to rif (which uses the same logic), there will be problems.

  arc> (rif (a b) (list 1 2) 'c 'd)
  Error: "Function call on inappropriate object 1 (2)"
  arc> (macex1 '(rif (a b) (list 1 2) 'c 'd))
  (let (a b) (list 1 2) (if (a b) (quote c) (quote d)))
It needs to be rewritten more like iflet.

  (mac rif (var expr . body)
    (w/uniq gv
      `(let ,gv ,expr
         (if ,gv
             (let ,var ,gv ,(car body))
             ,(if (cddr body)
                  `(rif ,var ,@(cdr body))
                  (cadr body))))))

  arc> (rif (a b) (list 1 2) (+ a b) 'c)
  3
  arc> (rif (a b) nil (+ a b) (list 3 4) (- a b))
  -1
  arc> (rif (a b) nil (+ a b) nil (- a b) 'c)
  c

-----

1 point by evanrmurphy 2689 days ago | link

Good catch.

-----

1 point by evanrmurphy 2691 days ago | link

Relatedly, why not define afn in terms of rfn?

  (mac afn (parms . body)
    `(rfn self ,parms ,@body))
Am I missing something here?

-----

2 points by waterhouse 2690 days ago | link

I'm guessing they defined afn because it was frequently useful, then defined rfn because they needed it "for use in macro expansions", and didn't find the refactoring worth their trouble.

Note, by the way, that rfn = "recursive fn" (that's the only reason you would use it instead of fn). But rif is certainly not "recursive if". If you still find it helps you remember it or that it makes more sense, sure, use it, but I would personally use iflet. (Or you could have it defined both ways and use whichever one your brain remembers first.)

-----

1 point by evanrmurphy 2690 days ago | link

Somehow it had escaped me that the r stood for "recursive". I thought maybe it stood for "reference", in which case rif would be a sensible name.

I think you're right this definition could just override iflet. It would be an obscure case where you wouldn't want var binding to the other exprs.

-----