Pergunta

Eu finalmente começou a aprender linguagens funcionais (Emacs Lisp) e faz distinção explícita entre as funções e formas especiais, tais como controle de fluxo, por exemplo se.

Existe uma razão fundamental / teórica por formas especiais são distintas das funções? fazer quaisquer linguagens fornecem if funcional?

Graças

Foi útil?

Solução

Com avaliação ansiosa a distinção é necessário, com línguas avaliação lenta (isto é, Haskell) se et al. podem ser funções.

avaliação ansiosa:. Argumentos da função são avaliadas antes de chamar a função, e apenas os resultados são passados ??para a função

preguiçoso de avaliação:. Argumentos de uma função avaliada se e somente se eles são acessados ??

Outras dicas

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.

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))

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.

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]> 

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.

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top