我正在尝试从 Haskell 中的输入中读取行,直到找到非空行。实际上,我知道如何简单地使用以下代码来做到这一点:
notEmpty [] = return ""
notEmpty (l:xs) = do
s <- l
if s /= "" then return s
else notEmpty xs
getLine' = notEmpty $ repeat getLine
测试(我输入了两个空行,然后是“foo”):
*> getLine'
foo
"foo"
但是,为了锻炼,我试图使用 Monoids(http://learnyouahaskell.com/functors-applicative-functors-and-monoids#monoids)来实现这一点,试图模仿 First/getFirst Monoids(见链接) .
我首先在满足我需要的列表上创建了一个 Monoid(连接只保留第一个参数):
newtype FirstSt a = FirstSt { getFirstSt :: [a] }
deriving (Eq, Ord, Read, Show)
instance Monoid (FirstSt a) where
mempty = FirstSt []
FirstSt [] `mappend` x = x
FirstSt s `mappend` _ = FirstSt s
它适用于无限的字符串列表(由于懒惰):
> getFirstSt . mconcat . map FirstSt $ ["", "", "foo", "", "bar"] ++ repeat ""
"foo"
但是,我无法让它在 IO Monad 中工作。我尝试了以下方法:
ioFirstSt = (=<<) (return . FirstSt)
getLine'' = getFirstSt <$> mconcat <$> (sequence . map ioFirstSt $ repeat getLine)
哪个具有正确的类型:
*> :t getLine''
getLine'' :: IO [Char]
然而,Haskell 一直想在将整个列表交给mconcat
...之前评估整个列表。有没有办法在 Monoid/Monad 范围内导航时保持懒惰?