我正在努力理解这个功能**
-- split at whitespace
-- f "hello world" -> ["hello","world"]
f = takeWhile (not . null) . evalState (repeatM $ modify (drop 1)
>> State (break (== ' '))) . (' ' :)
where repeatM = sequence . repeat
Run Code Online (Sandbox Code Playgroud)
我已经在努力理解状态单子,并且缺乏类型签名和无点风格使其更加令人困惑。
这里发生了什么?
** 取自这里
break (== ' ') :: String -> (String, String)生成输入字符串的最长前缀,左侧不带空格,其余后缀位于右侧。显然,我们希望以某种方式迭代此过程,将字符串拆分为单词。
State (break (== ' ')) :: State String String充当状态计算的视图。请记住State :: (s -> (a, s)) -> State s a,因此输出状态是正确的组件。因此,初始状态是输入字符串,并且break (== ' ')必须将其视为一个State操作,returns 第一个单词并将状态更新为剩余的后缀。
现在用 组合modify (drop 1)删除下一个空格,然后重复。(' ' :)请注意,它附加到开头的输入,并以modify
(sequence . repeat) (modify (drop 1) >> State (break (== ' ')))
:: State String [String]
= do
-- current_state = " hello wold"
modify (drop 1)
-- current_state = "hello world"
s1 <- State (break (== ' ')) -- s1 = "hello"
-- current_state = " world"
modify (drop 1)
-- current_state = "world"
s2 <- State (break (== ' ')) -- s2 = "world"
-- current_state = ""
modify (drop 1)
-- current_state = ""
s3 <- State (break (== ' ')) -- s3 = ""
-- current_state = ""
...
Run Code Online (Sandbox Code Playgroud)
repeat构造相同两步操作的无限列表,modify (drop 1) >> State (break (== ' '))
sequence获取操作列表并运行它们,将结果收集在列表中。在这里我挥手致意,但因为这是惰性状态单子(有一个严格的状态单子,但不是它),所以事情会顺利进行,以便sequence可以运行无限的操作列表并根据需要生成无限的结果列表。
因此,您将得到如上所示的无限计算,产生所有State (break (== ' '))步骤结果的无限列表。
["hello", "world", "", "", ...]
Run Code Online (Sandbox Code Playgroud)
takeWhile (not . null)希望是自我描述性的:它从列表中获取不为空的元素。
["hello", "world"]
Run Code Online (Sandbox Code Playgroud)