我希望在Haskell中拥有“return”(命令式语言中的)函数。
例如:
我该如何实现这个目标?
例如:
main = do
let a = 10
print a
-- return this function
print $ a + 1
我该如何实现这个目标?
main = do
let a = 10
print a
-- return this function
print $ a + 1
Exception
进行某种程度的模拟。{-# 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
单子变换器 来完成,尽管它们可能有些笨重。Either e
单子,而单子是建模控制流的绝佳选择。虽然我同意你的观点,即OP试图在Haskell中编写命令式代码,就好像它是<通用命令式语言>,并且在这种情况下使用异常可能是错误的。 - cdkEither e
与异常进行比较。Either e
是显式的,而异常是隐式的,这是一个巨大的区别。对于错误和正常行为,请使用 Either
,对于异常行为,请使用异常。 - mariopIO
单子中的异步异常,而不是在ErrorT
或EitherT
单子中的显式同步异常。我在阅读Rufflewind的回答时有点匆忙。在这种情况下,当然你是正确的。 - cdk首先,我要警告的是,试图将命令式结构翻译成Haskell可能会导致不符合惯用法、难以编写和难以阅读的代码。仅仅因为您可以使用几个monad转换器模拟一些结构,并不意味着这样做就应该实际操作。
话虽如此,下面是一个使用Control.Monad.Cont.ContT
进行早期返回的示例。以下代码在几个for循环中模拟了一个命令式返回。
正如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
IO
来完成这个任务。你可以将其与ErrorT
或ContT
结合使用来实现。或者你可以使用Exception
。 - RufflewindIO
实现,但有些Monad可以。具体而言,请查看MonadPlus
类型类,定义了提前退出的行为。正如您所见,IO
不是实现此类型类的其中之一。您可以查看MonadError
类型类,它来自mtl
库的另一个实现,定义了引发错误的行为,并提供了几个实例。 - bheklilr