ПОЗВОЛЬТЕ по сравнению с ПОЗВОЛЕННЫМ* в языке Common LISP

78
задан pupeno 13 May 2009 в 08:48
поделиться

10 ответов

LET самостоятельно не реальный примитив в Язык Функционального программирования , так как он может замененный LAMBDA. Как это:

(let ((a1 b1) (a2 b2) ... (an bn))
  (some-code a1 a2 ... an))

подобно [1 122]

((lambda (a1 a2 ... an)
   (some-code a1 a2 ... an))
 b1 b2 ... bn)

, Но

(let* ((a1 b1) (a2 b2) ... (an bn))
  (some-code a1 a2 ... an))

подобно [1 124]

((lambda (a1)
    ((lambda (a2)
       ...
       ((lambda (an)
          (some-code a1 a2 ... an))
        bn))
      b2))
   b1)

, можно вообразить, который является более простой вещью. LET а не LET*.

LET делает код, понимающий легче. Каждый видит набор привязки, и можно считать каждую привязку индивидуально без потребности понять top-down/left-right поток 'эффектов' (повторные переплетения). Используя [1 110] сигналы программисту (тот, который читает код), что привязка весьма зависима, но существует некоторый нисходящий поток - который усложняет вещи.

язык Common LISP имеет правило, что значения для привязки в [1 111] вычисляются слева направо. Как значения для вызова функции оценены - слева направо. Так, LET концептуально более простой оператор, и он должен использоваться по умолчанию.

Типы в [1 113] ? Используются довольно часто. Существуют некоторые примитивные формы описания типа, которые легко помнить. Пример:

(LOOP FOR i FIXNUM BELOW (TRUNCATE n 2) do (something i))

Выше объявляет, что переменная i fixnum.

Richard P. Gabriel опубликовал свою книгу по сравнительным тестам Lisp в 1985, и в то время эти сравнительные тесты также использовались с неCL, Шепелявит. Сам язык Common LISP был совершенно новым в 1985 - книга CLtL1, которая описала язык, был просто опубликован в 1984. Неудивительный реализации не были очень оптимизированы в то время. Реализованная оптимизация была в основном тем же (или меньше), который реализации прежде имели (как MacLisp).

, Но для [1 116] по сравнению с [1 117] основное различие - то, что код с помощью [1 118] легче понять для людей, так как обязательные пункты независимы друг от друга - тем более, что это - плохой стиль для использования в своих интересах левых к правильной оценке (не устанавливающий переменные как побочный эффект).

80
ответ дан Rainer Joswig 6 November 2019 в 03:08
поделиться

Я главным образом использую, ПОЗВОЛЯЮТ, если я specifgically не должен ПОЗВОЛИТЬ*, но иногда я пишу код, которому явно потребности ПОЗВОЛЯЮТ, обычно при выполнении различный (обычно сложный) установка по умолчанию. К сожалению, у меня нет удобного примера кода под рукой.

-1
ответ дан Vatine 6 November 2019 в 03:08
поделиться

По-видимому, при помощи let компилятор имеет больше гибкости для переупорядочения кода, возможно, для улучшений скорости или пространства.

Стилистически, с помощью параллельной привязки показывает намерение, что привязка группируется; это иногда используется в сохранении динамических связываний:

(let ((*PRINT-LEVEL* *PRINT-LEVEL*)
      (*PRINT-LENGTH* *PRINT-LENGTH*))
  (call-functions that muck with the above dynamic variables)) 
4
ответ дан Doug Currie 6 November 2019 в 03:08
поделиться

я иду один шаг вперед и использую , связывают , который объединяет let, let*, multiple-value-bind, destructuring-bind и т.д., и это даже расширяемо.

обычно мне нравится использовать "самую слабую конструкцию", но не с let & друзья, потому что они просто дают шум коду (субъективность, предупреждающая! никакая потребность попытаться убедить меня в противоположном...)

8
ответ дан Will Ness 6 November 2019 в 03:08
поделиться

Основное различие в общем Списке между ПОЗВОЛЕННЫМ и ПОЗВОЛИЛО*, то, что символы в ПОЗВОЛЕННОМ связываются параллельно, и в ПОЗВОЛЕННОМ* связываются последовательно. Используя ПОЗВОЛЕННЫЙ не позволяет init-формам выполняться параллельно, и при этом это не позволяет порядку init-форм быть измененным. причина состоит в том, что язык Common LISP позволяет функциям иметь побочные эффекты. Поэтому порядок оценки важен и всегда слева направо в форме. Таким образом, в ПОЗВОЛЕННОМ, init-формы оценены сначала, слева направо, затем привязка создается, слева направо параллельно. В ПОЗВОЛЕННОМ*, init-форма оценена и затем связана с символом в последовательности, слева направо.

CLHS: Специальный оператор ПОЗВОЛИЛ, ПОЗВОЛИЛ*

9
ответ дан Will Ness 6 November 2019 в 03:08
поделиться

В LISP часто существует требование использовать самые слабые конструкции. Некоторые руководства по стилю скажут Вам использовать =, а не eql, когда Вы будете знать, что сравненные объекты являются числовыми, например. Идея состоит в том, чтобы часто указывать то, что Вы имеете в виду, а не программируете компьютер эффективно.

Однако могут быть фактические улучшения эффективности высказывания только, что Вы имеете в виду, и не использование более сильных конструкций. Если у Вас есть инициализации с LET, они могут быть выполнены параллельно, в то время как LET* инициализации должны быть выполнены последовательно. Я не знаю, сделают ли какие-либо реализации на самом деле это, но некоторые могут хорошо в будущем.

11
ответ дан David Thornley 6 November 2019 в 03:08
поделиться

Я приезжаю, перенося изобретенные примеры. Сравните результат этого:

(print (let ((c 1))
         (let ((c 2)
               (a (+ c 1)))
           a)))

с результатом выполнения этого:

(print (let ((c 1))
         (let* ((c 2)
                (a (+ c 1)))
           a)))
24
ответ дан Will Ness 6 November 2019 в 03:08
поделиться

Вы не делаете , потребность ПОЗВОЛИЛА, но Вы обычно хотите она.

ПОЗВОЛЯЮТ, предполагает, что Вы просто делаете стандартную параллельную привязку ни с чем хитрое продолжение. ПОЗВОЛЬТЕ*, вызывает ограничения на компилятор и намекает пользователю, что существует причина, что необходима последовательная привязка. С точки зрения стиль , ПОЗВОЛЬТЕ, лучше, когда Вам не нужны дополнительные ограничения, введенные LET*.

может быть более эффективно использовать, ПОЗВОЛЯЮТ, чем ПОЗВОЛЕННЫЙ* (в зависимости от компилятора, оптимизатора, и т.д.):

  • параллельная привязка может быть выполнена в параллели (но я не знаю, делают ли какие-либо системы LISP на самом деле это, и формы init должны все еще быть выполнены последовательно)
  • , параллельная привязка создает единственную новую среду (объем) для всей привязки. Последовательная привязка создает новые вложенные условия для каждой привязки. Параллельное использование привязки меньше памяти и имеет более быстрый переменный поиск .

(Вышеупомянутые пункты маркированного списка относятся к Схеме, другому диалекту LISP. clisp может отличаться.)

33
ответ дан Mr Fooz 6 November 2019 в 03:08
поделиться
(let ((list (cdr list))
      (pivot (car list)))
  ;quicksort
 )

Конечно, это сработает:

(let* ((rest (cdr list))
       (pivot (car list)))
  ;quicksort
 )

И это:

(let* ((pivot (car list))
       (list (cdr list)))
  ;quicksort
 )

Но важна именно мысль.

4
ответ дан 24 November 2019 в 10:29
поделиться

В дополнение к ответу Rainer Joswig и с пуристской или теоретической точки зрения. Let и Let* представляют две парадигмы программирования; функциональную и последовательную соответственно.

Что касается того, почему я должен продолжать использовать Let* вместо Let, ну, вы лишаете меня удовольствия приходить домой и думать на чистом функциональном языке, в отличие от последовательного языка, с которым я провожу большую часть своего рабочего дня :)

.
1
ответ дан 24 November 2019 в 10:29
поделиться