空でない行が見つかるまで、Haskell の入力から行を読み取ろうとしています。実際、次のコードを使用して簡単に行う方法を知っています。
notEmpty [] = return ""
notEmpty (l:xs) = do
s <- l
if s /= "" then return s
else notEmpty xs
getLine' = notEmpty $ repeat getLine
テスト(2行の空行を入力してから「foo」を入力しました):
*> getLine'
foo
"foo"
ただし、演習のために、Monoids ( http://learnyouahaskell.com/functors-applicative-functors-and-monoids#monoids ) を使用してこれを達成しようとしています。First/getFirst 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モナドで動作させることはできません。私は次のことを試しました:
ioFirstSt = (=<<) (return . FirstSt)
getLine'' = getFirstSt <$> mconcat <$> (sequence . map ioFirstSt $ repeat getLine)
正しいタイプは次のとおりです。
*> :t getLine''
getLine'' :: IO [Char]
しかし、Haskell は、リスト全体を評価してから、リスト全体を評価したいと考えていmconcat
ます。