Почему ocaml нужны и «let», и «let rec»? [дубликат]

38
задан Community 23 May 2017 в 10:31
поделиться

1 ответ

Что ж, если оба они доступны вместо одного, это дает программисту более жесткий контроль над областью действия. В let x = e1 in e2 привязка присутствует только в среде e2, в то время как в let rec x = e1 in e2 привязка присутствует как в средах e1, так и e2.

(Изменить: я хочу подчеркнуть, что это не проблема производительности, которая не имеет никакого значения вообще.)

Вот две ситуации, когда это не рекурсивное связывание полезно:

  • дублирование существующего определения с уточнением, использующим старое связывание. Что-то вроде: let f x = (let x = sanitize x in ...), где sanitize - это функция, которая гарантирует, что вход имеет некоторое желаемое свойство (например, оно принимает норму возможно ненормализованного вектора и т. Д.). Это очень полезно в некоторых случаях.

  • метапрограммирование, например, написание макросов. Представьте, что я хочу определить макрос SQUARE(foo), который вводится в let x = foo in x * x, для любого выражения foo. Мне нужна эта привязка, чтобы избежать дублирования кода в выходных данных (я не хочу, чтобы SQUARE(factorial n) вычислял factorial n дважды). Это гигиенично, только если привязка let не является рекурсивной, в противном случае я не смог бы написать let x = 2 in SQUARE(x) и получить правильный результат.

Итак, я утверждаю, что действительно очень важно иметь как рекурсивное, так и нерекурсивное связывание. Теперь поведение let-привязки по умолчанию является предметом соглашения. Можно сказать, что let x = ... является рекурсивным, и для получения нерекурсивного связующего нужно использовать let nonrec x = .... Выбор одного или другого по умолчанию зависит от того, какой стиль программирования вы предпочитаете, и есть веские причины для того, чтобы сделать любой выбор. Haskell страдает от недоступности этого нерекурсивного режима, и OCaml имеет точно такой же дефект на уровне типа: type foo = ... является рекурсивным, и нет доступных нерекурсивных опций - см. это сообщение в блоге .

¹: когда Google Code Search был доступен, я использовал его для поиска в коде на Haskell шаблона let x' = sanitize x in .... Это обычный обходной путь, когда нерекурсивное связывание недоступно, но это менее безопасно, потому что вы рискуете позже написать x вместо x' по ошибке - в некоторых случаях вы хотите, чтобы оба были доступны, поэтому выбираете другое Имя может быть добровольным. Хорошая идиома - использовать более длинное имя переменной для первого x, например, unsanitized_x. В любом случае, просто поиск x' буквально (без имени другой переменной) и x1 дали много результатов. У Эрланга (и всех языков, которые пытаются затруднить теневое копирование: Coffeescript и т. Д.) Проблемы еще хуже.

Тем не менее, выбор наличия рекурсивных привязок Haskell по умолчанию (а не нерекурсивных), безусловно, имеет смысл, поскольку это согласуется с отложенной оценкой по умолчанию, что позволяет действительно легко создавать рекурсивные значения - в то время как строгие языки по умолчанию имеют больше ограничений на рекурсивные определения.

37
ответ дан 27 November 2019 в 03:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: