这是对 ContT 的适当使用吗?
Is this an appropriate use of ContT?
我正在从事一个需要我编写一个小型解释器的项目。这些指令具有简单的树结构,其中一个命令具有停止执行的效果。所以在下面的例子中,"baz" 永远不会被打印出来。
import Control.Monad.Cont
data Instruction = Print String | Halt | Block [Instruction]
deriving (Eq, Show)
instructions =
[ Print "foo"
, Block
[ Print "bar"
, Halt
]
, Print "baz"
]
main :: IO ()
main = runContT (callCC $ interpret instructions)
(const $ pure ())
interpret [] k = pure ()
interpret (a:as) k = case a of
Print str -> liftIO (putStrLn str) >> interpret as k
Block ins -> interpret ins k >> interpret as k
Halt -> k ()
这是我第一次在我的一个项目中看到 ContT
的潜在用途。我想知道这是否适合使用它,或者是否有我可能忽略的更简单的解决方案。
是的,这看起来正是 Control.Monad.Cont
适合的用例类型。
您几乎肯定知道这一点,但对于其他读者来说,值得说明的是,如果您编写了 interpret
,那么它是一个从指令列表到 [=13= 的函数] 像这样:
main :: IO ()
main = interpret instructions
interpret :: [Instruction] -> IO ()
interpret [] = pure ()
interpret (a:as) = case a of
Print str -> putStrLn str >> interpret as
Block ins -> interpret ins >> interpret as
Halt -> pure ()
然后 foo
bar
和 baz
都会打印出来。您需要的是一种转义机制,允许您中止整个计算并立即 return 一个值。这正是 callCC
提供的。调用命名计算(k
在你的代码中)允许你逃避整个计算,而不仅仅是 level/layer.
太棒了,我相信您在这里找到了 ContT 的合适用例。
我正在从事一个需要我编写一个小型解释器的项目。这些指令具有简单的树结构,其中一个命令具有停止执行的效果。所以在下面的例子中,"baz" 永远不会被打印出来。
import Control.Monad.Cont
data Instruction = Print String | Halt | Block [Instruction]
deriving (Eq, Show)
instructions =
[ Print "foo"
, Block
[ Print "bar"
, Halt
]
, Print "baz"
]
main :: IO ()
main = runContT (callCC $ interpret instructions)
(const $ pure ())
interpret [] k = pure ()
interpret (a:as) k = case a of
Print str -> liftIO (putStrLn str) >> interpret as k
Block ins -> interpret ins k >> interpret as k
Halt -> k ()
这是我第一次在我的一个项目中看到 ContT
的潜在用途。我想知道这是否适合使用它,或者是否有我可能忽略的更简单的解决方案。
是的,这看起来正是 Control.Monad.Cont
适合的用例类型。
您几乎肯定知道这一点,但对于其他读者来说,值得说明的是,如果您编写了 interpret
,那么它是一个从指令列表到 [=13= 的函数] 像这样:
main :: IO ()
main = interpret instructions
interpret :: [Instruction] -> IO ()
interpret [] = pure ()
interpret (a:as) = case a of
Print str -> putStrLn str >> interpret as
Block ins -> interpret ins >> interpret as
Halt -> pure ()
然后 foo
bar
和 baz
都会打印出来。您需要的是一种转义机制,允许您中止整个计算并立即 return 一个值。这正是 callCC
提供的。调用命名计算(k
在你的代码中)允许你逃避整个计算,而不仅仅是 level/layer.
太棒了,我相信您在这里找到了 ContT 的合适用例。