Очевидно Concurrent a
такая же, как Cont Action a
где Cont
является продолжением монады. Вот простое объяснение продолжений:
- Рассмотрим функцию
f :: a -> b
для некоторых произвольных типов a
и b
. Мы хотим преобразовать эту функцию в стиль продолжения передачи. Как мы это делаем?
- Предположим, что у нас есть продолжение
k :: b -> r
, которое принимает возвращаемое значение f
в качестве входа и само возвращает значение произвольного типа r
. После этого мы можем конвертировать f
в CPS.
- Позвольте
g :: a -> (b -> r) -> r
быть функцией версии CPS от f
. Обратите внимание, что он принимает дополнительный аргумент (т. Е. Продолжение k
) и возвращает результат k
, примененный к его выходу b
.
Давайте рассмотрим практический пример, где f
является функция предиката odd :: Int -> Bool
:
odd :: Int -> Bool
odd n = n `mod` 2 == 1
Вот та же функция, написанная в продолжении прохождения стиля:
odd' :: Int -> (Bool -> r) -> r
odd' n k = k (n `mod` 2 == 1)
(Bool -> r) -> r
часть может быть абстрагированы в качестве продолжения монады:
data Cont r a = Cont { runCont :: (a -> r) -> r }
odd' :: Int -> Cont r Bool
odd' n = return (n `mod` 2 == 1)
instance Monad (Cont r) where
return a = Cont (\k -> k a)
m >>= f = Cont (\k -> runCont m (\a -> runCont (f a) k))
Обратите внимание, что тип продолжения k
: Bool -> r
для произвольного типа r
. Следовательно, продолжением k
может быть любая функция, которая принимает аргумент Bool
. Например:
cont :: Bool -> IO()
cont = print
main :: IO()
main = odd' 21 cont
Однако, в случае Concurrent
это r
не является произвольным. Он специализировался на Action
. На самом деле, мы можем определить Concurrent
как тип синоним Cont Action
следующим образом:
type Concurrent = Cont Action
Теперь нам не нужно реализовать экземпляр Monad
для Concurrent
, потому что это то же самое, как Monad
например, для Cont r
, как определено выше ,
runConcurrent :: Concurrent a -> ContinuationPseudoMonad a
runConcurrent (Concurrent g) = g
instance Monad Concurrent where
return a = Concurrent (\k -> k a)
m >>= f = Concurrent (\k -> runConcurrent m (\a -> runConcurrent (f a) k))
Обратите внимание, что нигде в определении instance Monad Concurrent
есть мы использовали Action
. Это потому, что Concurrent = Cont Action
и пример монады Cont r
использует r
прозрачно.
Возникает вопрос, как определить 'return' и' >> = 'для' Concurrent', как вы определили его выше? – rampion
Кроме того, небольшая опечатка - я думаю, вы имеете в виду «данные Concurrent a = Concurrent (ContinuationPseudoMonad a)», поскольку «данные Concurrent a = Concurrent ContinuationPseudoMonad a' являются ошибкой. – rampion
Я исправил в соответствии с вашим заявлением. Дело в том, что мне не удается понять, что такое «Продолжение a -> Действие». Название этой абстракции было бы здорово. –