【问题标题】:Unwrapping the Haskell State Monad解开 Haskell State Monad
【发布时间】:2013-05-16 02:54:00
【问题描述】:

在为大学写作业的过程中,我一直在享受学习新的 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 使用的自定义数据类型/

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

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

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

【问题讨论】:

    标签: haskell


    【解决方案1】:

    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 progs 将是相同的。如果这不正确,您也可以将初始状态作为参数传递。

    【讨论】:

    • 完美的家伙。除了一件小事,它用“let s1 = evalState (compile prog) initialState”编译,而不是“let s1 = evalState $ compile prog initialState”。另一个问题 - 其他单子是否有这样的功能?即打开 monad 并只返回结果的函数?
    • @nebffa 完全取决于所讨论的 monad,但是是的,其中一些确实如此。这不是你可以对所有单子做的事情。另一个例子是可怕的 unsafePerformIO 用于 IO monad,但你不应该使用它。
    • 啊,对,把括号弄混了(先忘了状态,然后添加的时候忘了交换$)。感谢您的提醒。对于许多单子来说,都有相应的功能,但不是全部。 IO 是没有这样的[嗯,有一个名字以unsafe 开头的,它真的是这个意思]。有runIdentityrunReaderrunWriterrunCont,……看看每个monad的文档有没有这样的功能。
    猜你喜欢
    • 1970-01-01
    • 2018-08-27
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 2012-06-30
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多