这是https://haskell.mooc.fi/训练
-- Ex 5: define the IO operation readUntil f, which reads lines from
-- the user and returns them as a list. Reading is stopped when f
-- returns True for a line. (The value for which f returns True is not
-- returned.)
--
-- Example in GHCi:
-- *Set11> readUntil (=="STOP")
-- bananas
-- garlic
-- pakchoi
-- STOP
-- ["bananas","garlic","pakchoi"]
readUntil :: (String -> Bool) -> IO [String]
readUntil f = todo
你能用do表示法给我一个提示/解决方案吗?我是do表示法的开始;条件逻辑";以及循环目前对我来说太复杂了。
非常感谢
只使用do表示法和条件语句,我找到了以下解决方案:
readUntil :: (String -> Bool) -> IO [String]
readUntil f = do x <- getLine;
if f x then (return []) else (do xs <- readUntil f
return (x : xs))
函数首先从前奏中读取一行getLine
,然后检查(f x)
是否为真。然后它只返回空列表。我们不能只写... if f x then [] ...
,因为[]
的类型不是IO [String]
,而是[String]
。要使[]
成为类型IO [String]
,我们可以使用函数return
或pure
,但使用do表示法时,我使用return
函数,因为它包含在Monad
类型类中。如果f x
等于False
,那么我们使用第二个do块一次又一次地递归调用该函数,直到我们得到f x == True
的输入,并因此返回空列表。do表示法是必要的,因为xs的类型必须是[String]
,而readUntil
的类型是IO [String]
。我们不能将:
("cons"(运算符与类型为IO String
的对象一起使用,因此不能生成我们想要的列表。然后,我们将x添加到所有其他输入的列表xs中,并返回它
关于函数readUntil
的更通用版本,它可以与任何monad(而不仅仅是IO
monad(一起工作,请参阅Will Ness 的评论