解开Haskell State Monad

6
在撰写大学作业的过程中,我正在愉快地学习新的Haskell单子。耶!!!
我有一个类型检查良好的函数:
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。

也许有一些巧妙的方法可以解开这个 state monad?也许可以重写“编译”,使其在运行过程中输入一些状态单子信息,但最终返回一个字符串(不包含任何单子)?

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

1个回答

11

compile prog 是在 State VarsState Monad 中的一个动作,因此您不能像这样在 IO do 块中使用它。在 do 块中,所有行都必须使用相同的 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都相同,则条件不正确。 如果这不是正确的方法,您还可以将初始状态作为参数传递。


1
不错伙计。除了一个小问题,“let s1 = evalState (compile prog) initialState” 可以编译,但不是“let s1 = evalState $ compile prog initialState”。还有一个问题-还有其他单子的函数吗?即,能解开单子并只返回结果的函数? - nebffa
@nebffa 完全取决于具体的单子,但是有些单子确实会。这不是你可以为所有单子通用的事情。另一个例子是针对 IO 单子的可怕的 unsafePerformIO,但你不应该使用它。 - Matthew Walton
啊,是的,括号搞混了(先忘记了状态,然后在添加时忘记交换 $)。感谢提醒。对于许多单子,都有相应的函数,但并非所有单子都有。IO 就是其中没有这样函数的一个 [好吧,有一个名字以 unsafe 开头的函数,它真的真的很不安全]。有 runIdentityrunReaderrunWriterrunCont 等等。查看每个单子的文档,看看是否有这样的函数。 - Daniel Fischer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接