Может быть функцией, а не специальной формой
Наконец-то я начал изучать функциональные языки (emacs lisp), и он делает явное различие между функциями и специальными формами, такими как управление потоком, например if.
Существует ли фундаментальная/теоретическая причина, почему особые формы отличаются от функций? любые языки предоставляют функциональные if
?
Спасибо
Ответы
Ответ 1
С нетерпеливой оценкой требуется различие, языки с ленивой оценкой (т.е. Haskell), если et al. могут быть функциями.
Простая оценка: аргументы функции вычисляются перед вызовом функции, и только результаты передаются функции.
Ленивая оценка: аргументы функции оцениваются тогда и только тогда, когда они доступны.
Ответ 2
Если if
была нормальной функцией, тогда оба ее аргумента - форма затем и форма else - были бы оценены ранее вызывая функцию if
, потому что правило оценка функции: оценить все аргументы для создания значений, затем предоставить эту последовательность значений в качестве аргументов к функции, обозначенной первым символом в списке.
Вместо этого с if
то, что вы хотите сделать, - это точно определить одну из форм then и else, а не и то, и другое. Чтобы подавить оценку того или другого, вам нужен макрос или специальная форма.
Ответ 3
В таких языках, как Emacs Lisp и Common Lisp, специальные формы являются встроенными языковыми конструкциями. У них есть разные правила оценки, которые вызовут обычные функции. Для обычных вызовов функций все аргументы оцениваются. Таким образом, вы не можете записать IF как нормальную функцию - условие определяет, какое условие оценивается. Также обычно вы не можете писать свои собственные специальные формы - в Common Lisp нет языковой конструкции для определения специальной формы (хотя отдельные реализации должны каким-то образом реализовать существующие. Это приводит к макросам. С макросами вы можете написать синтаксическое преобразование, которое преобразует одно выражение в другое. Чтобы иметь возможность писать IF как макрос, вам нужно иметь другую условную форму, которую вы можете использовать для преобразованного кода. Lisp предоставляет условные обозначения в качестве базовых конструкций. Предположим, что COND is такая базовая конструкция, то вы могли бы расширить IF в использование COND.
MY-IF как макрос в Common Lisp:
(defmacro my-if (condition true-clause false-clause)
`(cond (,condition ,true-clause)
(t ,false-clause)))
Итак,
(my-if (foo-p) 'one 'two)
расширяется в
(cond ((foo-p) 'one)
(t 'two))
Ответ 4
Короткий ответ: Нет.
Long (er) answer: (if...) требует, чтобы вы контролировали порядок оценки аргументов. Lisp, будучи нетерпеливым языком, не может сделать это в функции.
Временное решение: сделайте это в макросе:
(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))))
Например:
[[email protected]:~]$ 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]>
Ответ 5
Для полноты: нет специальных форм в Pico, например, и if
является примитивной функцией, а Pico вдохновлен Scheme и по умолчанию оценивает оценку.
В схеме вы можете написать
(define (true t f)
(t))
(define (false t f)
(f))
(define (function_if c t e)
(c t e))
а затем
(function_if true (lambda () 'true) (lambda () 'false))
==> true
Что делает это управляемым в Pico, так это то, что вы можете определить функциональные параметры, которые автоматически заменяют функциональные аргументы. Это означает, что вам не нужно делать обертывание внутри лямбда. Поэтому Пико имеет нетерпеливую оценку, но с ленивой оценкой по требованию, минуя необходимость в специальных формах.
Итак, в синтаксисе Scheme с функциональными параметрами вы можете кодировать логические значения как:
(define (true (t) (f))
(t))
(define (false (t) (f))
(f))
Тогда функция if становится:
(define (function_if c (t) (e))
(c (t) (e)))
и
(function_if true 'true 'false)
==> true
В качестве другого примера определение функции and
составляет (define (and p (q)) (p (q) false))
.
Аналогичным образом вы можете определить or
, not
, while
, for
,... как функции, используя приведенную выше кодировку булевых.
Ответ 6
В Scala можно моделировать if
с правильной оценкой побочных эффектов, используя аргументы по имени.
def If[A](cond : Boolean, truePart : => A, falsePart : => A) = if (cond) truePart else falsePart
Эти функции могут использоваться для моделирования большого количества новых структур управления.
Ответ 7
IF может быть функцией на функциональном языке, имеющем семантику по имени (ленивая оценка), как в Lambda Calculus или Algol. На самом деле это, я думаю, в основе отношений между Turing Machines и Lambda Calculus как эквивалентные основы для вычислений. Однако в языках, имеющих побочные эффекты (например, присвоения переменным), это не очень полезно, потому что, когда все происходит, важно.