在为大学编写作业的过程中,我有一种学习新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中)?
如果我遗漏了任何信息,请告诉我。
答案 0 :(得分:11)
compile prog
是State 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
都是相同的。如果这不是正确的事情,你也可以将初始状态作为参数传递。