Arc Forumnew | comments | leaders | submitlogin
Generalizing iflet
4 points by akkartik 4567 days ago | 3 comments
A year ago I wondered how to best express this pattern:

  (let x (...)
    (when (f x)
       ..))
(http://www.arclanguage.org/item?id=16070)

Current solution:

  (whenlet x (...) :satisfies f
     ..)
Thoughts?

Implementation: https://github.com/akkartik/wart/commit/48336c2ca2



3 points by fallintothis 4566 days ago | link

Looking for a vanilla Arc solution, if

  (whenlet var expr ...)
is the same (modulo multiple evaluation) as

  (when expr
    (let var expr ...))
then it kind of makes sense to call

  (let var expr
    (when (f var) ...))
the same name in the opposite direction, like

  (letwhen (f var) var expr ...)
I.e.,

  (mac letwhen (test var expr . body)
    `(let ,var ,expr
       (when ,test ,@body)))

  (letwhen (even x) x 50
    (prn "I print"))

  (letwhen (even (+ x 1)) x 50
    (prn "I don't print"))
Alas, it's very clunky to read. I think Haskell makes this sort of code look nice, because you can have a postfix variable declaration, like

  blah = if (f var) then ... else ...
    where var = expr
So, maybe something like

  (when (f var) :where var = expr
    ...)
would do away with the extra level of indentation.

-----

3 points by akkartik 4566 days ago | link

1. I like your final solution! But no reason why either of ours couldn't be done in vanilla arc.

2. (whenlet var expr ...) could also be written:

  (let var expr
    (when var ...))
So I don't think letwhen is strictly necessary.

3. Another alternative formulation is:

  (let var expr :when (f var)
    ...)
All that's really saving us is a couple of parens compared to the original pattern. Maybe we don't need a macro, just a different indentation convention:

  (let var expr (when (f var)
    ...))
But both these make the conditional nature of the block harder to see. My original solution and yours don't have that drawback.

-----

1 point by akkartik 4560 days ago | link

After playing with it some more, I'm finding that this actually works better in arc than in wart. In wart perhaps I should require parenthesizing it differently:

  (iflet x ((...) :satisfies f)
             'branch1)
Otherwise it interacts poorly with paren-insertion. Things like this with multiple branches:

  iflet x 2+3 :satisfies even?
            x+1
          3+4 :satisfies even?
            x+2
=> (iflet x 2+3 :satisfies even? x+1 (3+4 :satisfies even?) x+2)

Need wrapping in parens lest the inner test get wrapped in parens:

  (iflet x 2+3 :satisfies even?
             x+1
           3+4 :satisfies even?
             x+2)
Hmm, unhappy with my choices here.

-----