0

I have a function which i must use and it is named :

hPutStrLn

That function has a type :

hPutStrLn::Handle -> String -> IO ()

And i what i wanted to do, it was using a shell command line grep and get the output and transmit to the String variable of hPutStrLn.

For example:

 tryA (arrIO (\s -> hPutDocument (\h-> hPutStrLn h (readProcess "grep" ["-n",s,"camera2.owl"] ""))))

But the problem is, that my readProcess has type of IO String, which must be a String if i wanna use the function hPutStrLn! And i don't know how i can solve this... So i have a few questions which is : -Could i extract the String from IO String ? - If i can't, is there any other way to do that ?

hPutDocument function

hPutDocument      :: (Handle -> IO ()) -> IO ()
      hPutDocument action
          | isStdout
              = do
                hSetBinaryMode stdout (not textMode)
                action stdout
                hSetBinaryMode stdout False
          | otherwise
              = do
                handle <- ( if textMode
                            then openFile
                            else openBinaryFile
                          ) dst WriteMode
                action handle
                hClose handle

isStdout  = null dst || dst == "-"

outFile   = if isStdout
            then "stdout"
            else show dst
Damiii
  • 1,363
  • 4
  • 25
  • 46

1 Answers1

4

The simplest approach is with do notation. You could define an auxiliary function to pass to hPutDocument:

doGrep :: Handle -> IO ()
doGrep h =
    do
        str <- readProcess "grep" ["-n",s,"camera2.owl"] ""
        hPutStrLn h str

tryA (arrIO (\s -> hPutDocument doGrep))

One way to think of it is that it allows you to convert an IO String to a String, but only within the scope of the do block, and the entire do block ends up having an IO type - IO () in this case.

You can't convert an IO String to a String in an arbitrary context, because Haskell's type system is designed to stop you from treating impure values that come from external sources being treated as pure - the IO type indicates that the value may have come from doing some kind of IO.

You can also use the >>= operator (pronounced "bind") directly in your call to hPutDocument:

hPutDocument (\h -> readProcess "grep" ["-n",s,"camera2.owl"] ""
                       >>= \str -> hPutrStrLn h str)

>>= has this type:

(>>=) :: IO a -> (a -> IO b) -> IO b

In this particular case, a = String and b = ().

So here >>= takes the IO String produced by readProcess ... and passes it to the second argument, which is a function that takes a String and produces an IO (). The overall result is the IO () produced by the second function.

The notation \str -> hPutStrLn h str defines an anonymous function (a "lambda") that takes str as an argument and produces the result of hPutStrLn h str.

The do notation above is actually translated ("desugared") to this by the compiler.

In this particular instance you can also shorten \str -> hPutrStrLn h str to just hPutStrLn h, and you could also use the reverse bind operator =<< to produce something as close as possible to your original code:

hPutDocument (\h -> hPutStrLn h =<< readProcess "grep" ["-n",s,"camera2.owl"] "")

Shortening \str -> hPutStrLn h str works because of partial application ("currying"). A function that takes multiple arguments can be just given some of them (in order), giving back a function that expects the remaining arguments.

Since hPutStrLn has type Handle -> String -> IO (), hPutStrLn h has type String -> IO (), so long as h has type Handle.

Ganesh Sittampalam
  • 28,821
  • 4
  • 79
  • 98
  • Firstly, thank you for your answer ! I must say that i'm trying to use an haskell functions made by HXT Library. And i'm reconverting it for my own purpose with my own objectives. One thing, that i didn't understand, was the use of (\s -> ... and (\h -> ... What does it mean ? Secondly, if i don't must use the `do notation`, i didn't understood quit properly your second approach with the `>>=`. – Damiii Jun 15 '14 at 15:01
  • I've expanded on my answer a bit to explain the syntax and concepts used, but if you have a question that's not specifically about my answer it's best to start a fresh StackOverflow question. – Ganesh Sittampalam Jun 15 '14 at 15:09
  • I edited my post with the function missing. And i still don't understand how could i use your `>>=` when `hPutDocument` need my `hPutStrLn`and you are telling me to do that `tryA ... >>= \str -> hPutrStrLn h str`. I'm a bit confused – Damiii Jun 15 '14 at 15:35
  • 1
    Apologies - I didn't read your question carefully enough (partly because the code was badly formatted - anything that produces ahorizontal scrollbar is hard to read!) and didn't notice that the hPutStrLn call was inside the code, not being used on the result. I've corrected my answer now. – Ganesh Sittampalam Jun 15 '14 at 15:45