6

在为大学写作业的过程中,我一直在享受学习新的 Haskell monads 的乐趣。耶!!!

我有一个可以很好地进行类型检查的函数:

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

说它无法将预期类型“IO t0”与实际类型“State VarsState String”匹配。

我认为这是因为 Maybe_compile_prog 返回类型 IO () 所以它只希望解开 IO 信息?VarsState 是我与 State monad/ 一起使用的自定义数据类型

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

也许有一些巧妙的方法来解开这个状态单子?也许可以重写“编译”,以便在运行时接收一些状态单子信息,然后只返回一个字符串(不包含在任何单子中)?

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

4

1 回答 1

11

compile progState VarsStatemonad 中的一个动作,因此您不能在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传递的 s 都是相同的。如果这不正确,您也可以将初始状态作为参数传递。

于 2013-05-21T11:11:09.897 回答