Продолжения в Clojure

Я где-то читал, где сказал богатый хикки:

"Я думаю, что продолжение может быть опрятным в теории, но не на практике"

Я не знаком с clojure.
1. Имеет ли clojure продолжения?
2. Если нет, вам не нужны продолжения? Я видел много хороших примеров, особенно из этого парня. Какая альтернатива?
3. Если да, есть ли документация?

Ответ 1

Говоря о продолжениях, вы должны различать два разных типа:

  • Первоклассные продолжения - поддержка продолжения, которая глубоко интегрирована в язык (схема или Ruby). Clojure не поддерживает первоклассные продолжения.

  • Continuation-pass-style (CPS) - CPS - это всего лишь стиль кодирования, и любой язык, поддерживающий анонимные функции, позволит использовать этот стиль (который также относится к Clojure).

Примеры:

-- Standard function
double :: Int -> Int
double x = 2 * x

-- CPS-function – We pass the continuation explicitly
doubleCPS :: Int -> (Int -> res) -> res
doubleCPS x cont = cont (2 * x)
; Call
print (double 2)

; Call CPS: Continue execution with specified anonymous function
double 2 (\res -> print res)

Прочитайте continuation в Википедии.

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

Ответ 3

Является ли продолжение необходимой функцией на языке?

Нет. Многие языки не имеют продолжений.

Если нет, вам не нужны продолжения? Я видел много хороших примеров, особенно от этого парня. Какая альтернатива?

Стек вызовов

Ответ 4

Общее использование продолжений заключается в реализации структур управления для: возврата из функции, выхода из цикла, обработки исключений и т.д. Большинство языков (таких как Java, С++ и т.д.) предоставляют эти функции как часть основного языка. На некоторых языках нет (например: Схема). Вместо этого эти языки выставляют непрерывность как объекты первого класса и позволяют программисту определять новые структуры управления. Таким образом, Схему следует рассматривать как инструментарий инструментария программирования, а не полный язык сам по себе.

В Clojure нам почти никогда не нужно использовать продолжения напрямую, потому что почти все структуры управления предоставляются комбинацией языка/виртуальной машины. Тем не менее, первоклассные продолжения могут стать мощным инструментом в руках компетентного программиста. Особенно в схеме, продолжения лучше, чем эквивалентные аналоги на других языках (например, пара setjmp/longjmp в C). Эта статья содержит более подробную информацию об этом.

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

Ответ 6

Абстрактные продолжения

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

Continuations описывают управляющие эффекты, такие как вызов/возврат функции, обработка исключений и даже gotos. Хороший язык, в частности, будет разработан с абстракциями, построенными на продолжениях (например, исключения). (То есть, обоснованный язык будет состоять из управляющих операторов, которые были разработаны с учетом продолжения. Разумеется, совершенно разумно, чтобы язык показывал продолжения как единственную контрольную абстракцию, позволяющую пользователям создавать собственные абстракции сверху.)

Продолжение первого класса

Если понятие продолжения reified как объект первого класса на языке, тогда у нас есть инструмент, на котором все виды могут быть созданы управляющие эффекты. Например, если язык имеет первоклассные продолжения, но не исключения, мы можем построить исключения поверх продолжений.

Проблемы с первичными продолжениями

В то время как первоклассные продолжения являются мощным и полезным инструментом во многих случаях, есть также некоторые недостатки в том, чтобы разоблачить их на языке:

  • Различные абстракции, построенные поверх продолжений, могут привести к неожиданному/неинтуитивному поведению при составлении. Например, блок finally может быть пропущен, если я использую продолжение, чтобы прервать вычисление.
  • Если текущее продолжение может быть запрошено в любое время, тогда время выполнения языка должно быть структурировано таким образом, чтобы в любое время можно было представить некоторое представление структуры данных текущего продолжения. Это накладывает определенную нагрузку на время выполнения функции, которая, к лучшему или худшему, часто считается "экзотической". Если язык размещен (например, Clojure размещен в JVM), то это представление должно соответствовать рамкам, предоставляемым платформой хостинга. Могут также быть и другие функции, которые язык хотел бы поддерживать (например, C interop), которые ограничивают пространство решения. Такие проблемы увеличивают потенциал "несоответствия импеданса" и могут серьезно осложнить разработку решения для исполнителей.

Добавление переходов первого класса к языку

С помощью метапрограммирования можно добавить поддержку первоклассных продолжений на язык. Как правило, этот подход включает в себя преобразование кода в стиль продолжения передачи (CPS), в котором текущее продолжение передается как явный аргумент для каждой функции.

Например, библиотека Дэвида Нолена delimc реализует разграниченные продолжения частей программы Clojure посредством серии макрообъектов. В аналогичном ключе я создал pulley.cps, который является макрокомпилятором, который преобразует код в CPS вместе с библиотекой времени выполнения для поддерживают более основные функции Clojure (такие как обработка исключений), а также взаимодействуют с собственным кодом Clojure.

Одной из проблем с этим подходом является то, как вы обрабатываете границу между нативным (Clojure) кодом и преобразованным (CPS) кодом. В частности, поскольку вы не можете зафиксировать продолжение собственного кода, вам необходимо либо запретить (или каким-то образом ограничить) взаимодействие с базовым языком, либо возложить на пользователя бремя, обеспечивающее, чтобы контекст позволял любому продолжению, которое они хотели бы захватить на самом деле быть захваченным.

pulley.cps имеет тенденцию к последнему, хотя некоторые попытки были сделаны, чтобы позволить пользователю управлять этим. Например, можно запретить код CPS для вызова в собственный код. Кроме того, предусмотрен механизм предоставления версий CPS существующих нативных функций.

В языке с достаточно сильной системой типов (например, Haskell) можно использовать систему типов для инкапсуляции вычислений, которые могут использовать операции управления (то есть продолжения) из функционально чистого кода.

Резюме

Теперь у нас есть информация, необходимая для прямого ответа на ваши три вопроса:

  • Clojure не поддерживает первоклассные продолжения из-за практических соображений.
  • Все языки построены на продолжениях в теоретическом смысле, но несколько языков выставляют продолжения как объекты первого класса. Тем не менее, можно добавлять продолжения к любому языку посредством, например, преобразования в CPS.
  • Ознакомьтесь с документацией для delimc и/или pulley.cps.

Ответ 7

Ну... Clojure -> реализует то, что вы после... Но вместо макроса