0

I am having an issue converting IO String() to a String() Below is the function to eval an expression.

foobar :: String -> IO String

eval :: String -> Sh () ()
eval x =  do
 s <- foobar x
 shellPutStrLn $ s

This isnt working, because eval returns IO String instead of Sh. The moment some IO is done within a function it transforms/taints it into IO String. How do I prevent the transformation or convert an IO String to String ?

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
icylisper
  • 35
  • 1
  • 3
  • What do you mean by IO String()? If you mean `IO String ()` that's not a valid type, and neither is `String()`. – Squidly May 10 '11 at 10:09
  • 1
    Are you trying to do something similar to http://donsbot.wordpress.com/2010/08/17/practical-haskell/ ? – tibbe May 10 '11 at 10:48
  • Duplicate of [Converting IO Int to Int](http://stackoverflow.com/questions/4235348/converting-io-int-to-int) and http://stackoverflow.com/questions/1675366/a-haskell-function-of-type-io-string-string and hundred other similar questions. Please use search – Landei May 10 '11 at 11:50
  • @Landei - The title is similar, but the problem's context is different and so is the solution. I don't think either of the questions you link to are appropriate as duplicates. Although this may be a duplicate of a monad transformer question... – John L May 10 '11 at 14:01
  • Over on Math.SE, they have something called 'abstract duplicates' for this kind of almost-but-not-quite repitition. – yatima2975 May 10 '11 at 16:48

3 Answers3

6

It looks like your Sh type is supposed to be able to do IO. The usual way to implement this is with monad transformers. Then you would have:

instance MonadIO Sh where -- definition elided because you don't show Sh

shellPutStrLn :: String -> Sh ()
shellPutStrLn = liftIO . putStrLn

eval :: String -> Sh ()
eval x = do
  s <- liftIO $ foobar x
  shellPutStrLn s

See the MTL for a lot of ready monad transformers you can use, and xmonad for a good example of this style in practice.

John L
  • 27,937
  • 4
  • 73
  • 88
3

This "tainting" of your string is deliberate and cannot be avoided without resorting to dirty hacks. You can extract the String temporarily, however, provided you put the result back in IO when you're done. For example

foobar :: String -> IO String

baz :: String -> IO Int
baz str = do
    result <- foobar str
    return (length result)

I would recommend reading up on Haskell IO

hammar
  • 138,522
  • 17
  • 304
  • 385
1

You can say that you are operating within some monad any time you use the 'do notation'. For example, the code below operates within the IO monad:

printThem x y = do
    print ("x: " ++ show x)
    print ("y: " ++ show y)

You can't mix monads in the same 'do' block. This is what you are attempting here.

eval :: String -> Sh () ()
eval x =  do          -- Which monad? There can be only one!
    s <- foobar x     -- IO monad
    shellPutStrLn $ s -- Sh monad

You will have to execute foobar in an outer layer. Use something like the following. I don't know where your Sh monad is coming from, so I'll just pretend that there is a runShell :: Sh () -> IO () function:

doSomeIO :: IO ()
doSomeIO = do
    s <- foobar x
    runShell $ shellPutStrLn s
Michael Steele
  • 15,512
  • 2
  • 23
  • 24