Haskell 中的这个一元函数是如何工作的?

mat*_*ias 4 haskell

我正在努力理解这个功能**

  -- 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)

我已经在努力理解状态单子,并且缺乏类型签名和无点风格使其更加令人困惑。

这里发生了什么?

** 取自这里

Li-*_*Xia 8

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)