worldterminator
worldterminator

Reputation: 3076

How to "break" IO action in haskell

I want to have the "return" (in imperative language) function in haskell.

E.g.

main = do
  let a = 10
  print a
--  return this function
  print $ a + 1

How can I achieve this?

Upvotes: 3

Views: 712

Answers (2)

chi
chi

Reputation: 116174

First, let me start by warning that trying to translate imperative constructs into Haskell will likely lead to code which is not idiomatic, hard to write, and hard to read. Just because you can simulate some constructs by using a few monad transformers, it does not mean that this should actually be done.

That being said, here's an example of early return using Control.Monad.Cont.ContT. The code below simulates an imperative return inside a few for loops.

As Rufflewind warns, this can get unwieldy. The type of callCC alone (not shown below) can be quite puzzling.

import Control.Monad.Cont

search :: Int -> IO (Maybe (Int,Int))
search x = runContT (callCC go) return
  where go earlyReturn = do
           forM_ [10..50] $ \i -> do
              lift $ putStrLn $ "Trying i=" ++ show i
              forM_ [10..50] $ \j -> do
                lift $ putStrLn $ "Trying j=" ++ show j
                when (i * j == x) $ do
                   lift $ putStrLn $ "Found " ++ show (i,j)
                   earlyReturn $ Just (i,j)
           return Nothing

Upvotes: 2

Rufflewind
Rufflewind

Reputation: 8966

You can emulate this to some extent using Exceptions,

{-# LANGUAGE DeriveDataTypeable #-}
import Control.Exception
import Data.Typeable

data MyException = MyException deriving (Show, Typeable)
instance Exception MyException

main = handle (\ MyException -> return ()) $ do
  let a = 10 :: Int
  print a
  throwIO MyException
  print $ a + 1         -- never gets executed

You can also do it with the ContT or ErrorT monad transformers, although they can a bit unwieldly.

Upvotes: 2

Related Questions