1

空でない行が見つかるまで、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ます。

4

1 に答える 1