打开Haskell State Monad

时间:2013-05-21 10:56:23

标签: haskell

在为大学编写作业的过程中,我有一种学习新Haskell monad的快乐乐趣。耶!!!

我有一个类似于typechecks的功能:

compile :: Prog -> State VarsState String
compile prog@(Prog functions) = do
    s1 <- sequence (map (translate_func 0) [get_function prog name | name <- [func_name func | func <- functions]])
    return $ trace ("here's the program: \n" ++ show prog) $ concat $ s1

但是当这个其他功能:

maybe_compile_prog ::
    MaybeOK Prog -> String -> IO ()
maybe_compile_prog (Error msg) _ = do
    putStrLn ("error: " ++ msg)
maybe_compile_prog (OK prog) modulename = do
    s1 <- compile prog
    writeFile (modulename ++ ".m") ((header modulename) ++ s1)

尝试调用它,它在行

处爆炸
s1 <- compile prog

说它不能与预期的类型匹配&#34; IO t0&#34;实际类型&#34;状态VarsState字符串&#34;。

我认为这是因为maybe_compile_prog返回类型IO()所以它只希望解包IO信息? VarsState是我用于状态monad /

的自定义数据类型

但是,如果这是问题,我认为是,我不知道如何将这个简单的字符串传递给maybe_compile_prog。真的,这就是我想做的 - 给一个字符串给maybe_compile_prog。

也许还有一些整齐的方式解开这个状态monad?或许可以重写&#34;编译&#34;这样它在运行时会收到一些状态monad信息,但是只返回一个字符串(不包含在任何monad中)?

如果我遗漏了任何信息,请告诉我。

1 个答案:

答案 0 :(得分:11)

compile progState VarsState monad中的操作,因此您无法在IO - do-block中使用它。在do-block中,所有行必须使用相同的monad,在本例中为IO

您需要“运行”compile操作以获取结果,并使用

之一
runState :: State s a -> s -> (a,s)
evalState :: State s a -> s -> a
execState :: State s a -> s -> s

取决于您是否需要

  • 结果和最终状态
  • 仅结果
  • 只有最终状态

在您的情况下,您只需要结果,因此evalState就是。

为此您需要提供初始状态,它可能看起来像

maybe_compile_prog (OK prog) modulename = do
    let s1 = evalState (compile prog) initialState
    writeFile (modulename ++ ".m") ((header modulename) ++ s1)

但是,compile操作提供的初始状态对于所有传递的OK prog都是相同的。如果这不是正确的事情,你也可以将初始状态作为参数传递。