Поскольку вы пометили это с помощью Haskell, я отвечу по этому поводу: в Haskell эквивалент преобразования CPS работает в монаде Cont
, которая преобразует значение x
в более высокое значение. Функция заказа, которая принимает один аргумент и применяет его к x
.
Итак, для начала вот 1 + 2 в обычном Haskell: (1 + 2)
А вот в монаде продолжения:
contAdd x y = do x' <- x
y' <- y
return $ x' + y'
... не очень информативно. Чтобы увидеть, что происходит, давайте разберем монаду. Сначала удалите запись do
:
contAdd x y = x >>= (\x' -> y >>= (\y' -> return $ x' + y'))
Функция return
выводит значение в монаду и в этом случае реализуется как \x k -> k x
, или с использованием секции инфиксного оператора как \x -> ($ x)
.
contAdd x y = x >>= (\x' -> y >>= (\y' -> ($ x' + y')))
Оператор (>>=)
(читай «связать») объединяет вычисления в монаде и в этом случае реализуется как \m f k -> m (\x -> f x k)
. Изменение функции связывания на префикс формы и подстановку в лямбду, а также некоторые переименования для ясности:
contAdd x y = (\m1 f1 k1 -> m1 (\a1 -> f1 a1 k1)) x (\x' -> (\m2 f2 k2 -> m2 (\a2 -> f2 a2 k2)) y (\y' -> ($ x' + y')))
Сокращение некоторых функций приложения:
contAdd x y = (\k1 -> x (\a1 -> (\x' -> (\k2 -> y (\a2 -> (\y' -> ($ x' + y')) a2 k2))) a1 k1))
contAdd x y = (\k1 -> x (\a1 -> y (\a2 -> ($ a1 + a2) k1)))
И немного финальной перестановки и переименования:
contAdd x y = \k -> x (\x' -> y (\y' -> k $ x' + y'))
Другими словами: аргументы функции были изменены с чисел на функции, которые принимают число и возвращают конечный результат всего выражения, как и следовало ожидать.
Редактировать : Комментатор указывает, что contAdd
сам по-прежнему принимает два аргумента в стиле карри. Это разумно, потому что оно не использует продолжение напрямую, но не обязательно. Чтобы сделать иначе, вам нужно сначала разбить функцию на части между аргументами:
contAdd x = x >>= (\x' -> return (\y -> y >>= (\y' -> return $ x' + y')))
А затем используйте это так:
foo = do f <- contAdd (return 1)
r <- f (return 2)
return r
Обратите внимание, что это действительно ничем не отличается от более ранней версии; это просто упаковывает результат каждого частичного применения как продолжение, а не только конечный результат. Поскольку функции являются первоклассными значениями, нет существенной разницы между выражением CPS, содержащим число, и выражением, содержащим функцию.
Имейте в виду, что я пишу здесь очень многословно, чтобы четко обозначить все шаги, где что-то происходит в стиле продолжения.
Добавление: вы можете заметить, что конечное выражение выглядит очень похоже на версию с моносами без десагаров. Это не совпадение, так как внутренняя вложенность монадических выражений, которая позволяет им изменять структуру вычислений на основе предыдущих значений, тесно связана со стилем прохождения продолжения; в обоих случаях вы в некотором смысле утвердили понятие причинности.