/ / Подходящо ли е използването на ContT? - haskell, monads, продължения

Това е подходящо използване на 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 в един от моите проекти. Чудех се дали това е подходящо използване от него или ако има по-просто решение, което може да се пренебрегне.

Отговори:

7 за отговор № 1

Да, това изглежда е точно такъв случай на използване Control.Monad.Cont е подходящо.

Почти сигурно сте наясно с това, но за други читатели си струва да се каже, че ако сте написали interpret така, че да е функция от списък с инструкции към IO () така:

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 всички щяха да печатат. Това, от което се нуждаете, е механизъм за бягство, който ще ви позволи да прекъснете цялото изчисление и веднага да върнете стойност. Точно това е callCC осигурява. Извикване на споменатото изчисление (k във вашия код) ви позволява да избягате от цялото изчисление, а не само това ниво / слой.

Толкова добра работа, намерих точно подходящия случай на използване на ContT тук, аз вярвам.