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


Я где-то читал, что Рич Хики сказал:

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

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

7 27

7 ответов:

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

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

  • Continuation-passing – 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)

ЧитайтеПродолжение в Википедии.

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

Я написал порт Clojure cl-cont, который добавляет продолжения к общему Лиспу.

Https://github.com/swannodette/delimc

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

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

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

Стек вызовов

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

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

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

Clojure (или, скорее, clojure.contrib.monads) имеет продолжение монады; Вот статья, которая описывает его использование и мотивацию .

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

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

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

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

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

Задачи с первоклассными продолжениями

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

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

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

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

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

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

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

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

Резюме

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

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

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