2

Hello i have done my JSon type and i am trying to it to a file. I can do this from the prelude but i can't do it when using the IO Monad.I get the following 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
   |                        ^^^

Main

 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

Why would this not work in the IO Monad since renderJValue sample in the prelude works ok .

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 returns a string

P.S: if i start the prelude i load the module and i render the value it works:

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]"
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152

1 Answers1

7

You here use renderJValue sample as if it is an IO String:

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

But it is in fact (given it is a function similar to this one) a function with signature renderJValue :: JValue -> String. So no IO is involved. In that case we do not use the arrow notation.

We can call the function "inline":

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

or even shorter:

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

But in case the expression is rather long, this can become quite ugly. We can decide to use a let statement in that case.

You can solve this by either removing the putStrLn:

main :: IO()
main = do
    let val = renderJValue sample
    writeFile out val
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Hey.I am sorry that was a typo.I updated the original post with further information. – Bercovici Adrian May 17 '18 at 08:20
  • Then the proposed solution is still valid: you need to use a `let` statement here, and not a `<-`, since `renderJValue` is (as far as I know) not monadic? – Willem Van Onsem May 17 '18 at 08:21
  • Is there any documentation on this?When to use `<-` vs `let` regarding monads? – Bercovici Adrian May 17 '18 at 08:22
  • 1
    @BercoviciAdrian: well the result of monadic actions are catched with `<-` for the others, you can decide to inline it (i.e. `writeFile out (renderJValue sample)`, but this leads to complicated code), or by using `let` statements, that act like a `let ... in ...` in non-`do` blocks. – Willem Van Onsem May 17 '18 at 08:23
  • I thought that inside the Monad you can not use `=` only `<-`.Outside monad i have used `let` and `where` clauses etc..i know these constructs but do not know how they are used in `IO`. – Bercovici Adrian May 17 '18 at 08:27
  • 1
    @BercoviciAdrian: well `do` notation is actually only syntactical sugar. If you write `do {x <- f; g x}`, you have actually written `f >>= g`. And like in non-do blocks, you can use a `let` clause. – Willem Van Onsem May 17 '18 at 08:29
  • 3
    Use `foo <- bar` whenever `bar` returns an *action* in the current monad (e.g., `IO Integer`). Use `let foo = bar` whenever `bar` does *not* return an action in the current monad (e.g., `Integer`). – MathematicalOrchid May 17 '18 at 08:31
  • Oh so to use `<- method` ,`method` has to have some side effects like doing some IO stuff on its own? So `method` should be `method::IO Something` where something is a type.In my case i could create a wrapper for `putStrLn ` that has a `do `inside it and it would work. – Bercovici Adrian May 17 '18 at 11:41
  • 1
    @BercoviciAdrian: more or less, although `do` works with other monadic types than `IO` like `Maybe` and `[]`, etc. (which makes it quite hard to understand at first). But you can say that it has to be an `IO Something`, whether it really has side effects is of no importance. – Willem Van Onsem May 17 '18 at 11:47