views:

196

answers:

7

hello

I finally started learning functional languages (emacs lisp) and it makes explicit distinction between functions and special forms such as flow control , for example if.

Is there a fundamental/theoretical reason why special forms are distinct from functions? do any languages provide functional if?

Thanks

+11  A: 

With eager evaluation the distinction is required, languages with lazy evaluation (i.e. Haskell) if et al. can be functions.

Eager evaluation: The function's arguments are evaluated before calling the function, and only the results are passed to the function.

Lazy evaluation: A function's arguments evaluated if and only if they are accessed.

gimpf
Call by name (Scala) works either.
Dario
Well, I never did anything in Scala, so I don't know any details. Still, I expect one has to specify whether an argument is evaluated lazily or not -- or does call-by-name have some other semantics? If yes, if you could provide a link beside the pure reference, I'd be very thankful.
gimpf
I think the underlying attribute is that of pure functionality: in a purely functional language, or in code using only pure functions (functions which return a value but have no side effects), `if` can be a function. Haskell's lazy evaluation is necessary for its functional purity.
Tim Schaeffer
Well, I always associated the _pure_ in "pure functional" with "no side effects possible" (except the I/O part...). It never came to me that lazy evaluation is _required_ for a pure functional language. Well, just another white place on my programming map... Somehow I start contemplating on giving up on all those issues.
gimpf
+6  A: 

If if was a normal function, then both its arguments -- the then form and the else form -- would both be evaluated before calling the if function, because that's the rule of function evaluation: evaluate all arguments to produce values, then provide that sequence of values as arguments to the function designated by the first symbol in the list.

Instead, with if what you want to do is evaluate exactly one of the then form and else form, not both. In order to suppress evaluation of one or the other, you need either a macro or a special form.

seh
A: 

Short answer: No.

Long(er) answer: (if ...) requires that you control the evaluation order of the arguments. Lisp, being an eager language cannot do this in a function.

Workaround: do it in a macro:

(defmacro _if (cnd true false)
    (let (  (gcond (gensym))
            (gresp (gensym)))
        `(let ( (,gcond ,cnd) ;`#quotes
                (,gresp nil))        
            (and ,gcond       (setf ,gresp (multiple-value-list ,true)))
            (and (not ,gcond) (setf ,gresp (multiple-value-list ,false)))
            (values-list ,gresp))))

For example:

[dsm@localhost:~]$ clisp -q
[1]> (defmacro _if (cnd true false)
    (let (  (gcond (gensym))
            (gresp (gensym)))
        `(let ( (,gcond ,cnd) ;`#quotes
                (,gresp nil))        
            (and ,gcond       (setf ,gresp (multiple-value-list ,true)))
            (and (not ,gcond) (setf ,gresp (multiple-value-list ,false)))
            (values-list ,gresp))))
_IF
[2]> (_if (= 1 1) (+ 2 3) "bar")
5
[3]> (_if (= 1 2) (+ 2 3) "bar")
"bar"
[4]> 
dsm
I think it would help to post working code in ANSWERs. Not only the syntax of your code is broken, also the logic.
Rainer Joswig
the logic is not flawed. (and ...) and (or ...) are already lazy. Syntax *was* broken tho.
dsm
Why does (_if t nil 3) return 3?
Rainer Joswig
Why does (let ((cond nil)) (_if cond t nil)) return T?
Rainer Joswig
Why does (defun foo (a b c) (_if a b c)) not compile?
Rainer Joswig
left as an exercise for the reader ;-)... But, basically, because fixing it so it works in all cases obscures the principle.
dsm
a gensym with the result of cond would fix it when combined to the 'false' expression
dsm
To me it looks like your OR/AND logic simply does not work. (_if t nil 'false) returns false instead of NIL. A basic IF that does not work is no IF, I'd say.
Rainer Joswig
Fair enough, fixed.
dsm
That's a bit better. I don't think you need the PROGN. In Common Lisp it is still not IF, since in Common Lisp (if t (truncate 3 4) t) returns 0 3 . In your macro it returns only 0.
Rainer Joswig
I think multiple values would be taking it a bit too far
dsm
but fixed it anyway :) and took out the (progn ...) too
dsm
My problem with this is that you're saying IF doesn't have to be a special form, but you're using AND. You can't get from the standard CL function (which evaluates everything) to IF (which doesn't evaluate everything) with macros (unless, of course, the condition can be evaluated at compile time). You need something that looks like a function but isn't, which in CL is a special form, and you can build from there. Since the original question was why special forms were necessary, and the IF was just an example, I just don't see this as an answer.
David Thornley
Have you read the text (rather than just the code) of the answer?
dsm
+1  A: 

For completeness: there are no special forms in the Pico language for example, and if is a primitive function while Pico is inspired by Scheme and has eager evaluation by default.

In Scheme you could write

(define (true t f)
  (t))

(define (false t f)
  (f))

(define (function_if c t e)
  (c t e))

and then

(function_if true (lambda () 'true) (lambda () 'false))
==> true

What makes this manageable in Pico is that you can define functional parameters that take functional arguments that are "automatically" delayed. This means that you don't have to do the wrapping inside lambdas yourself. Pico therefore has eager evaluation but with lazy evaluation on demand, bypassing the need for special forms.

So, in Scheme syntax with functional parameters you can encode booleans as:

(define (true (t) (f))
  (t))

(define (false (t) (f))
  (f))

Then function if becomes:

(define (function_if c (t) (e))
  (c (t) (e)))

and

(function_if true 'true 'false)
==> true

As another example, the definition of the function and is (define (and p (q)) (p (q) false)).

Similarly you can define or, not, while, for, ... as functions, using the above encoding of booleans.

eljenso
+3  A: 

In languages like Emacs Lisp and Common Lisp, special forms are built-in language constructs. They have different evaluation rules that normal function calls. For normal function calls all arguments are evaluated. So, you can't write an IF as a normal function - the condition determines which clause gets evaluated. Also usually you can't write your own special forms - in Common Lisp there is no language construct for defining a special form (though individual implementations must have implemented the existing ones somehow. This leads to macros. With macros you can write a syntactic transformation that transforms one expression into another one. To be able to write IF as a macro, you need to have another conditional form, which you can use for the transformed code. Lisp provides conditionals as basic constructs. Let's assume COND is such a basic construct, then you could expand IF into a usage of COND.

MY-IF as a macro in Common Lisp:

(defmacro my-if (condition true-clause false-clause)
   `(cond (,condition ,true-clause)
          (t ,false-clause)))

So

(my-if (foo-p) 'one 'two)

gets expanded into

(cond ((foo-p) 'one)
      (t 'two))
Rainer Joswig
A: 

In Scala it's possible to model if with correct side-effect evaluation using call-by-name arguments.

def If[A](cond : Boolean, truePart : => A, falsePart : => A) = if (cond) truePart else falsePart

These feature can be used to model lots of new control structures as well.

Dario
A: 

IF could be a function in a functional language having call-by-name semantics (lazy evaluation), as in Lambda Calculus or Algol. In fact that is, I think, at the heart of the relationship between Turing Machines and Lambda Calculus as equivalent foundations for computing. However, in languages having side-effects (like assignments to variables) it is not much use, because when things happen is important.

Mike Dunlavey