Arc Forumnew | comments | leaders | submitlogin
1 point by diiq 5468 days ago | link | parent

Your first thought is correct.

    (map if '(t nil) '((pr "a") (pr "b")))
returns

    ((pr "b"))
because you've quoted the arguments. This is consistent; if you quote the arguments to if, you will get the same result (as you pointed out). Why would you expect a quoted argument to be evaluated?

The point is, just as you say, that you can pass functions which are normally considered 'special' and they will behave like any other function. Yeah, it's been done before (though you'll notice that picolisp comes up pretty often in your Google search; it's a canonical example) --- but that doesn't make it a bad idea; it's one less thing for the user to keep track of. I watched a person give up learning CL when they tried to pass a special form and discovered, after much frustration, that it was impossible.



1 point by fallintothis 5466 days ago | link

This is consistent [...] Why would you expect a quoted argument to be evaluated?

I misspoke regarding consistency. What I meant was that the "useful" way (conditionally evaluating the branches) would be inconsistent, but the consistent way doesn't seem very useful (because the point of special forms is to behave specially).

Yeah, it's been done before [...] but that doesn't make it a bad idea

Certainly not! I didn't mean to imply first-class macros/special forms are a bad idea --- let alone just because they've been done before. I meant that the ideas are similar; since there's been more discussion about first-class macros, it might be useful to ponder those.

Even so, first-class special forms seem less promising than first-class macros. rntz already pointed out that functions can mimic PicoLisp's behavior for special forms, but you can even mimic the "useful" behavior for certain cases of if:

  arc> (def iffn (x y z) (if (eval x) (eval y) (eval z)))
  #<procedure: iffn>
  arc> (iffn '(prn "test") '(prn "then") '(prn "else"))
  test
  then
  "then"
  arc> (iffn '(do1 nil (prn "test")) '(prn "then") '(prn "else"))
  test
  else
  "else"
But that's still kind of a joke. And what about ones that don't even evaluate their arguments, like fn? If

  (car:map if '(t) '((pr "a")))
corresponds to

  (if 't '(pr "a"))
then does

  (car:map fn '(t) '((pr "a")))
correspond to

  (fn 't '(pr "a"))
which isn't even valid syntax? (At least by the way Arc's quote and fn interact; I understand PicoLisp's quote and fn are unified to just quote.)

I'm not against first-class special forms iff we can reason about them. It's just that reasonable interpretations look like solutions in search of the problem.

-----

1 point by rntz 5468 days ago | link

It's consistent, but it means that passing special forms to higher-order functions is essentially just a form of punnery - it lends you no more expressiveness. There is no way (unless I'm mistaken) to get (map if '(t nil) X), where X is some expression, to evaluate the first element of X (or its evaluation) but not the second. So I could as well just define a function:

    (def iffn a
      (iflet (c . a) a
        (iflet (x . a) a
          (if c x (apply iffn a))
          c)))
    
    (map iffn '(t nil) '(1 2) '(5 6))
    => (1 6)

-----