Я работал с учебником Олега продолжения с разделителями:
newtype Cont r a = Cont{runCont :: (a -> r) -> r}
instance Monad (Cont r) where
return x = Cont (\k -> k x)
Cont m >>= f = Cont (\k -> m (\v -> runCont (f v) k))
runC :: Cont r r -> r
runC m = runCont m id
reset :: Cont a a -> Cont r a
reset = return . runC
shift :: ((a -> r) -> Cont r r) -> Cont r a
shift f = Cont (runC . f)
liftM2 (-)
(reset
(liftM2 (+) (return 3)
(shift (\k -> return (5*2))))) -- drop the continuation
(return 1) -- 9
Поскольку продолжения в основном являются функциями, а reset
/ shift
даже не являются частью monad api, мне интересно, как реализовать продолжения с разделителями без newtype
и механизма монады.
Вот что я придумал:
reset :: Cont a a -> Cont r a -- becomes
reset :: ((a -> a) -> a) -> (a -> r) -> r
reset k f = f $ k id
shift :: ((a -> r) -> Cont r r) -> Cont r a -- becomes
shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift f k = f k id
Я почти уверен, что это неправильно, и если нет, я не знаю, как правильно применять операторы:
(1-) (reset ((3+) (shift (\k -> 5*2)))) -- yields
• Non type-variable argument in the constraint: Num ((a -> a) -> a)
(Use FlexibleContexts to permit this)
• When checking the inferred type
t1 :: forall a r.
(Num ((a -> a) -> a), Num ((a -> r) -> r)) =>
(a -> r) -> r