我正在玩Prelude中的interact
函数,想要逐行评估我的输入,我无法理解发生了什么。
如果我这么简单:
main :: IO ()
main = interact interaction
interaction :: String -> String
interaction (x:xs) = xs
interaction x = x
然后它表现正常,并从输入中删除第一个字符,如果只有一个字符长则返回输入。
让我感到困惑的是如果添加这一行:
interaction :: String -> String
interaction x | length x > 10 = "long word" -- this line causes problem
interaction (x:xs) = xs
interaction x = x
然后,交互似乎不再能够正常工作。 它只是等待我的输入,吞下它等待另一个输入等等,但从不输出任何内容。
然而,这似乎很简单,但我看不出有什么问题。 有什么想法吗?
(在我的路上我有GHC 7.6.3,我不知道它是否有一些重要性。)
答案 0 :(得分:3)
根据您所编写的内容,您正在尝试计算整个输入序列的长度,因此您的程序必须等待整个序列可用。
您可以尝试这样的懒惰模式匹配:
interaction (x1:x2:x3:x4:x5:x6:x7:x8:x9:x10:x11:_) = "long word"
一旦您知道已达到10个字符,就可以忽略输入的其余部分。
更清洁/更通用的替代方案(由@amalloy建议),可扩展更大的长度并允许可变长度的防护,如下所示:
interaction xs | not . null . drop 10 $ xs = "long word"
如果您真正想要做的是一次处理输入一行,并为超过10个字符的单个行生成此消息,则可以使用lines
和unlines
来制作交互功能面向行而不是面向字符,例如:
main :: IO ()
main = interact (unlines . interaction . lines)
interaction :: [String] -> [String]
interaction (x:_) | length x > 10 = "long word" -- this is just looking at the first line
...
或者如果你想为每一行做这件事,而不仅仅是第一行:
main :: IO ()
main = interact (unlines . map interaction . lines)
interaction :: String -> String
interaction x | length x > 10 = "long word"
...
答案 1 :(得分:3)
interact
一次取整个标准输入,作为一个大字符串。您在所有stdin上调用length
,因此在stdin完全耗尽之前,您的函数无法返回。例如,您可以点击ctrl-D(假设Unix)发送EOF,然后您的函数将最终找出stdin的长度。