Обычные плюсы применяются, когда мы можем предположить чистоту и ссылочную прозрачность. Мы можем автоматически запоминать горячие точки. Мы можем автоматически распараллелить вычисления. Мы можем справиться со многими условиями гонки. Мы также можем использовать совместное использование структур с данными, которые, как мы знаем, не могут быть изменены, например, (квази) примитиву ``cons()'' не нужно копировать cons-ячейки в списке, к которому он относится. На эти клетки никак не влияет наличие другой cons-ячейки, указывающей на них. Этот пример довольно очевиден, но компиляторы часто хорошо разбираются в более сложном совместном использовании структур.
Однако на самом деле определить, является ли лямбда (функция) чистой или имеет ссылочную прозрачность, в Common Lisp очень сложно. Помните, что funcall (foo bar) начинается с просмотра (symbol-function foo). Итак, в этом случае
(defun foo (bar)
(cons 'zot bar))
foo() чистый.
Следующая лямбда тоже чистая.
(defun quux ()
(mapcar #'foo '(zong ding flop)))
Однако позже мы можем переопределить foo:
(let ((accu -1))
(defun foo (bar)
(incf accu)))
Следующий вызов quux() уже не является чистым! Старый чистый foo() был переопределен в нечистую лямбду. Угу. Этот пример может быть несколько надуманным, но нередко лексически переопределяют некоторые функции, например, с помощью блока let. В этом случае невозможно узнать, что произойдет во время компиляции.
Common Lisp имеет очень динамическую семантику, поэтому на самом деле определить поток управления и поток данных заранее (например, при компиляции) очень сложно, а в большинстве полезных случаев совершенно невозможно решить. Это довольно типично для языков с динамическими системами типов. В Лиспе есть много общих идиом, которые вы не можете использовать, если вы должны использовать статическую типизацию. В основном это мешает любой попытке провести осмысленный статический анализ. Мы можем сделать это для примитивов, таких как минусы и друзья. Но для лямбда-выражений, включающих другие вещи, кроме примитивов, мы находимся в гораздо более глубоком положении, особенно в тех случаях, когда нам нужно посмотреть на сложное взаимодействие между функциями. Помните, что лямбда является чистой только в том случае, если все лямбды, которые она вызывает, также являются чистыми.
На мой взгляд, с помощью некоторой глубокой макрологии можно было бы избавиться от проблемы переопределения. В некотором смысле, каждая лямбда получает дополнительный аргумент, который является монадой, представляющей полное состояние лисп-образа (очевидно, что мы можем ограничиться тем, на что на самом деле будет смотреть функция). Но, вероятно, полезнее иметь возможность объявлять чистоту самостоятельно, в том смысле, что мы обещаем компилятору, что эта лямбда действительно чистая. Последствия, если это не так, не определены, и могут возникнуть всевозможные погромы ...
person
Community
schedule
31.08.2011
!
...Я годами думал, что главное отличие CL от Scheme в чистоте...потом все мои надежды и мечты рухнули, когда я научился читайте в инете. - person Keith Layne   schedule 31.08.2011