一个do-block中有多个monad

Mar*_*vič 10 haskell

我目前正在尝试学习Haskell,我真的无法理解在do-block中只使用一个monad的概念.如果我有foo :: Int -> Maybe Int并且想hIsEOF :: Handle -> IO Bool在这个函数中使用例如函数.有人可以在一些基本的例子上向我解释我将如何使用hIsEOF并可以某种方式使用Bool

我一直试图在这里和谷歌搜索,但我总是遇到一些高级的东西,基本上没有人解释如何,他们只是给出如何适应OP的代码的建议.我看到那些线程中提到的monad变换器,但即使在阅读了一些资源之后,我似乎也找不到如何使用它们的正确方法.

beh*_*uri 12

使用monad变形金刚,您需要做的就是

  1. 将函数签名更改Int -> Maybe Int

    foo :: Int -> MaybeT IO Int
    
    Run Code Online (Sandbox Code Playgroud)
  2. 解除do块内的所有IO操作(或者liftIO在这种情况下).看看为什么你需要这个提升,它究竟是什么.

  3. 使用运行该功能 runMaybeT

一个最小的例子是:

import Control.Monad.Trans (lift)
import Control.Monad.Trans.Maybe (MaybeT, runMaybeT)

import System.IO (openFile, hClose, hSeek, hIsEOF)
import System.IO (IOMode(ReadMode), SeekMode(AbsoluteSeek))

foo :: Int -> MaybeT IO Int
foo i = do
    h <- lift $ openFile "test.txt" ReadMode
    -- move the handle i bytes ahead
    lift . hSeek h AbsoluteSeek $ fromIntegral i
    eof <- lift $ hIsEOF h  -- check if hit end of file
    lift $ hClose h
    if eof then fail "eof!" else return i
Run Code Online (Sandbox Code Playgroud)

然后,

\> runMaybeT $ foo 1
Just 1
\> runMaybeT $ foo 100  -- would hit eof
Nothing
Run Code Online (Sandbox Code Playgroud)

你得到的是这种类型:

(runMaybeT . foo) :: Int -> IO (Maybe Int)
Run Code Online (Sandbox Code Playgroud)

  • @MarekMilkovič理想情况下只有极少数小功能应该做IO.其他一切都应该是纯粹的 (2认同)

PyR*_*lez 7

最简洁的答案是不.记谱法基于两件事

return :: a -> m a
>>= :: m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)

请注意>>=,尽管您可以使用两种不同的内部类型(ab),但它只适用于一种外部类型,一种是monad(m).这两个m aa -> m b是相同的单子.

答案越长,你必须将它们转换为相同的monad.例如,Maybe可以转换为IO如此:

maybeToIO Nothing = error "No thing"
maybeToIO (Just a) = return a
Run Code Online (Sandbox Code Playgroud)

一般来说,Monads不能相互转换,特殊情况除外.


那么为什么>>=只与一个monad一起工作呢?好吧,看看这个.它被定义为一次使用单个monad,并且定义了do-notation >>=.选择这个定义的原因有点复杂,但如果有人想要,我可以编辑它.

你可以想出你自己的>>=多个monad,然后使用可重新绑定的语法,但这可能很难.

  • 它也可能有助于看到符号如何被标准化为标准的monadic运算符.https://en.wikibooks.org/wiki/Haskell/Syntactic_sugar#Do_notation (2认同)
  • @MarekMilkovič请注意,您可以将它们转换为*第三个*monad.这就是behzad.nouri正在做的事情.他将"IO"和"也许"转换为"MaybeT IO",这是两个monad的融合. (2认同)