icylisper
icylisper

Reputation: 35

transforming IO String to String

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 ?

Upvotes: 0

Views: 3590

Answers (3)

Michael Steele
Michael Steele

Reputation: 15772

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

Upvotes: 1

hammar
hammar

Reputation: 139840

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

Upvotes: 3

John L
John L

Reputation: 28097

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.

Upvotes: 6

Related Questions