私は小さなインタプリタを書く必要があるプロジェクトに取り組んでいます。命令は単純なツリー構造を持ち、コマンドの1つは実行を中止する効果があります。下の例では、 "baz"は決して印刷されません。これはContTの適切な使用ですか?
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
のための潜在的な使用を見てきたの初めてです。私はこれが適切かどうか、あるいは単純な解決策が見過ごされるかもしれないかどうか疑問に思っていました。
唯一のジャンプ命令が「停止」の場合、「例外」を使用して簡単に行うことができます。それとは別に、継続モナドは一般的に通訳者にはあまり適していません。 – Alec
これは問題ありません。上記のように 'k 'を変更する必要がなければ、リスト全体に対して' traverse_'や 'mapM_'を使ってみることができます。 'k()'は '' early return ''の効果のために '' k()>> ... 'と同じであるので、リスト全体を(遅延的に)トラバースするのは同等でなければならないことに注意してください。 – chi