如何仅用纯函数来表达分隔的延续?
How to express delimited continuations with pure functions only?
我完成了 Oleg 的 tutorial 定界延续:
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
继续加油!
import Prelude hiding (return)
-- reset :: Cont a a -> Cont r a
reset :: ((a -> a) -> a) -> (a -> r) -> r
reset k f = f $ k id
-- shift :: ((a -> r) -> Cont r r) -> Cont r a
shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift f k = f k id
-- return :: a -> Cont r a
return :: a -> (a -> r) -> r
return a k = k a
-- liftM2 :: (a -> b -> c) -> Cont r a -> Cont r b -> Cont r c
liftM2 :: (a -> b -> c) -> ((a -> r) -> r) -> ((b -> r) -> r) -> (c -> r) -> r
liftM2 f ma mb k = ma $ \a -> mb $ \b -> k (f a b)
example :: Num a => (a -> r) -> r
example = liftM2 (-) (reset (liftM2 (+) (return 3) (shift (\k -> return (5*2))))) (return 1)
(1-) (reset ((3+) (shift (\k -> 5*2))))
的一个问题是您将 Cont
的 return
替换为 id
,而实际上 flip id
:
λ :t shift (\k -> 5*2)
shift (\k -> 5*2) :: Num ((r -> r) -> r) => (a -> r) -> r
λ :t shift (\k -> ($ 5*2))
shift (\k -> ($ 5*2)) :: Num r => (a -> r) -> r
通常,当 ghci 说 "we need to be able to treat functions as numbers for this code to work" 时,这意味着你在某个地方犯了错误 :)
我完成了 Oleg 的 tutorial 定界延续:
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
继续加油!
import Prelude hiding (return)
-- reset :: Cont a a -> Cont r a
reset :: ((a -> a) -> a) -> (a -> r) -> r
reset k f = f $ k id
-- shift :: ((a -> r) -> Cont r r) -> Cont r a
shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift f k = f k id
-- return :: a -> Cont r a
return :: a -> (a -> r) -> r
return a k = k a
-- liftM2 :: (a -> b -> c) -> Cont r a -> Cont r b -> Cont r c
liftM2 :: (a -> b -> c) -> ((a -> r) -> r) -> ((b -> r) -> r) -> (c -> r) -> r
liftM2 f ma mb k = ma $ \a -> mb $ \b -> k (f a b)
example :: Num a => (a -> r) -> r
example = liftM2 (-) (reset (liftM2 (+) (return 3) (shift (\k -> return (5*2))))) (return 1)
(1-) (reset ((3+) (shift (\k -> 5*2))))
的一个问题是您将 Cont
的 return
替换为 id
,而实际上 flip id
:
λ :t shift (\k -> 5*2)
shift (\k -> 5*2) :: Num ((r -> r) -> r) => (a -> r) -> r
λ :t shift (\k -> ($ 5*2))
shift (\k -> ($ 5*2)) :: Num r => (a -> r) -> r
通常,当 ghci 说 "we need to be able to treat functions as numbers for this code to work" 时,这意味着你在某个地方犯了错误 :)