【问题标题】:Can not print to file using IO Monad无法使用 IO Monad 打印到文件
【发布时间】:2018-10-27 09:44:22
【问题描述】:

您好,我已经完成了我的 JSon 类型,我正在尝试将其写入文件。 我可以从前奏中做到这一点,但在使用 IO Monad 时我不能这样做。我得到以下error:

 Main.hs:13:24: error:
    * Couldn't match type `Char' with `[Char]'
      Expected type: String
        Actual type: Char
    * In the second argument of `writeFile', namely `val'
      In a stmt of a 'do' block: writeFile out val
      In the expression:
        do val <- renderJValue sample
           writeFile out val
   |
13 |          writeFile out val
   |                        ^^^

主要

 module Main where
        import Jlib
        import Put
        import Data.Typeable

        import System.Environment

        out="data.txt"

        main::IO()
        main=do
             val<-renderJValue sample
             writeFile out val

为什么这在 IO Monad 中不起作用,因为前奏中的 renderJValue sample 可以正常工作。

Jlib.hs

data JValue=JString String
                |JNumber Double
                |JBool Bool
                |JNull
                |JObject [(String,JValue)]
                |JArray [JValue]
                deriving (Eq,Ord,Show)

Put.hs

sample=JArray[
                    JObject [("name",JString "adita"),("age",JNumber 13)],
                    JObject [("name",JString "dan"),("kids",JNumber 3)] ,
                    JNumber 3,
                    JBool False,
                    JString "Howdy"
                    ]

P.S renderJValue 返回一个字符串

PS:如果我开始前奏,我会加载模块并渲染它的工作值:

Prelude System.Environment Put> :load Put
Ok, two modules loaded.
Prelude System.Environment Put> renderJValue sample
"[{name:adita,age:13.0},{name:dan,kids:3.0},3.0,False,Howdy]"

【问题讨论】:

    标签: haskell monads do-notation


    【解决方案1】:

    你在这里使用renderJValue sample,就好像它是IO String:

    main :: IO()
    main=do
         val <- renderJValue sample
         writeFile out val

    但实际上(假设它是一个类似于this one 的函数)签名为renderJValue :: JValue -&gt; String 的函数。所以不涉及IO。在这种情况下,我们不使用箭头符号。

    我们可以调用函数“inline”:

    main :: IO()
    main = do
         writeFile out (renderJValue sample)

    甚至更短:

    main :: IO()
    main = writeFile out (renderJValue sample)

    但如果表达式相当长,这可能会变得非常难看。在这种情况下,我们可以决定使用let 语句。

    您可以通过删除 putStrLn: 来解决此问题:

    main :: IO()
    main = do
        let val = renderJValue sample
        writeFile out val

    【讨论】:

    • 嘿。很抱歉这是一个错字。我用更多信息更新了原始帖子。
    • @BercoviciAdrian: 单子动作的结果被&lt;- 捕获,你可以决定内联它(即writeFile out (renderJValue sample),但这会导致复杂的代码),或者使用let 语句,在非 do 块中的行为类似于 let ... in ...。
    • @BercoviciAdrian:do 符号实际上只是语法糖。如果你写do {x &lt;- f; g x},你实际上写了f &gt;&gt;= g。就像在非执行块中一样,您可以使用let 子句。
    • 只要bar 在当前单子中返回一个action,就使用foo &lt;- bar(例如IO Integer)。只要bar 在当前单子中不返回一个动作(例如Integer),就使用let foo = bar。
    • @BercoviciAdrian: 或多或少,尽管do 可以与IO 以外的其他单子类型一起使用,例如Maybe 和[] 等(一开始很难理解) .但是你可以说一定是IO Something,是否真的有副作用并不重要。
    猜你喜欢
    • 1970-01-01
    • 2023-03-18
    • 2021-09-20
    • 2021-04-03
    • 1970-01-01
    • 2014-07-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多