К каким последствиям приведет обращение со специальными формами как с нормальными значениями?

Я обнаружил, что специальные формы нельзя передавать в качестве аргументов или сохранять в переменных, как в Clojure:

user=> (defn my-func 
         [op] 
         (op 1 2 3))
#'user/my-func
user=> (my-func +)
6
user=> (my-func if)
java.lang.Exception: Unable to resolve symbol: if in this context (NO_SOURCE_FILE:5)
user=> (def my-if if)
java.lang.Exception: Unable to resolve symbol: if in this context (NO_SOURCE_FILE:9)

и в Racket/Scheme:

> (define (my-func op)
    (op 1 2 3))
> (my-func +)
6
> (my-func if)
  if: bad syntax in: if
> (define my-if if)
  *if: bad syntax in: if

Это круто, меня это устраивает, я знаю, что могу просто написать функцию для обертывания специальной формы, а затем передать эту функцию.

Но я хотел бы знать, почему Лиспы имеют это ограничение, и какие негативные последствия это может иметь. Есть ли какие-либо основные диалекты, которые позволяют это?


person Matt Fenwick    schedule 04.07.2012    source источник


Ответы (2)


Это усложняет оценку и усложняет компиляцию.

Если у вас есть форма (a b c), то вам нужно разрешить во время выполнения значение a, а затем каким-то образом применить его к формам b и c.

Простая модель с несколькими ограниченными формами и строгой оценкой исчезает.

См. также: FEXPR.

person Rainer Joswig    schedule 04.07.2012

Специальные формы не являются функциями: функции принимают значения в качестве аргументов, тогда как специальные формы принимают формы. Например, посмотрите на свой пример if:

(if 1 2 3)

Хорошо, это просто, так как 2 и 3 уже являются значениями. Но как насчет этого?

(define (modadd a b n)
  (if (zero? n) #f (modulo (+ a b) n)))

В этом случае if фактически получает #f и (modulo (+ a b) n) как формы, а не как значения. И это важно! (modulo x n) потерпит неудачу, если n равно 0: вот почему оно остается невычисленным до тех пор, пока мы не узнаем, что n не равно 0.

Проблема с возможностью передавать специальные формы в качестве объектов первого класса заключается в том, что функции более высокого порядка не могут вызывать эти объекты, используя предсказуемую семантику: является ли это объектом функции, так что вы передаете значения, или это особая форма, так что вы проходите в формах? Получается огромный беспорядок.

Да, вы можете написать функцию-оболочку, такую ​​как моя modadd, которая инкапсулирует if. Тем не менее, вы не можете просто переопределить if как функцию, сохраняя при этом поведение «только оценка одной из ветвей».

person Chris Jester-Young    schedule 04.07.2012