Как "разбить" действие IO в haskell

Я хочу иметь функцию возврата (в императивном языке) в haskell.

например.

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

Как я могу это достичь?

2 ответа

Вы можете эмулировать это в некоторой степени, используя Exception s,

{-# 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

Вы также можете сделать это с помощью ContT или ErrorT monad transformers, хотя они могут немного нечестно.


Во-первых, позвольте мне начать с предупреждения о том, что попытка перевести императивные конструкции в Haskell, скорее всего, приведет к коду, который не является идиоматическим, трудно писать и трудно читается. Просто потому, что вы можете имитировать некоторые конструкции, используя несколько трансформаторов монады, это не значит, что это действительно должно быть сделано.

При этом здесь приведен пример раннего возвращения с использованием Control.Monad.Cont.ContT. Приведенный ниже код имитирует императивный возврат внутри нескольких циклов.

Как предупреждает Rufflewind, это может стать громоздким. Тип callCC один (не показан ниже) может быть довольно озадачивающим.

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

licensed under cc by-sa 3.0 with attribution.