想知道互动用法

时间:2016-09-07 21:48:38

标签: haskell

我正在玩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,我不知道它是否有一些重要性。)

2 个答案:

答案 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个字符的单个行生成此消息,则可以使用linesunlines来制作交互功能面向行而不是面向字符,例如:

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的长度。