Keeping IO lazy under append

前端 未结 2 1109
天命终不由人
天命终不由人 2021-01-19 03:42

I may have been under the false impression that Haskell is lazier than it is, but I wonder if there\'s a way to get the best of both worlds...

Data.Monoid

2条回答
  •  广开言路
    2021-01-19 04:06

    The Alternative instance for the MaybeT monad transformer returns the first successful result, and does not execute the rest of the operations. In combination with the asum function, we can write something like:

    import Data.Foldable (asum)
    import Control.Applicative
    import Control.Monad.Trans.Maybe
    
    action :: Char -> IO Char
    action c = putChar c *> return c
    
    main :: IO ()
    main = do
        result <- runMaybeT $ asum $ [ empty
                                     , MaybeT $ action 'x' *> return Nothing
                                     , liftIO $ action 'v'
                                     , liftIO $ action 'z'
                                     ]
        print result
    

    where the final action 'z' won't be executed.

    We can also write a newtype wrapper with a Monoid instance which mimics the Alternative:

    newtype FirstIO a = FirstIO (MaybeT IO a)
    
    firstIO :: IO (Maybe a) -> FirstIO a
    firstIO ioma = FirstIO (MaybeT ioma)
    
    getFirstIO :: FirstIO a -> IO (Maybe a)
    getFirstIO (FirstIO (MaybeT ioma)) = ioma
    
    instance Monoid (FirstIO a) where
        mempty = FirstIO empty
        FirstIO m1 `mappend` FirstIO m2 = FirstIO $ m1 <|> m2
    

    The relationship between Alternative and Monoid is explained in this other SO question.

提交回复
热议问题