Haskell的跨度函数

Haskell's span function

我对 Haskell 比较陌生,我正在努力寻找一种方法来实现 Haskell 的 span 功能。但是,我的问题比那个更普遍,因为我不知道如何使函数 return 成为包含我想要的元素的列表列表或元组列表。我的列表列表问题,例如:

[[1],[2]]

是我无法让函数将元素添加到列表列表中的第一个列表。我只知道如何将另一个列表附加到列表列表中。

简而言之,如果您向我解释如何实现 span 功能,我应该会清楚这一切。

所以我认为你所说的是你知道如何通过做类似

的事情递归地附加到列表
foobar :: [x] -> [y]
foobar (  []) = []
foobar (x:xs) = {- ...stuff... -} : foobar xs

但您不知道如何使用 两个 列表:

foobar :: [x] -> ([y], [z])
foobar (x:xs) = ???

一般来说,当结果不是一个列表,而是包含一个列表的东西时,你最终会做这样的事情:

foobar :: [x] -> ([y], [z])
foobar (x:xs) =
  let
    y = {- whatever -}
    z = {- whatever -}
    (ys, zs) = foobar xs   -- The recursive call
  in  (y:ys, z:zs)

如果结果是单子动作,同样适用

foobar :: [x] -> IO [y]
foobar (x:xs) = do
  y  <- {- whatever -}
  ys <- foobar xs
  return (y:ys)

请注意,这会强制函数不惰性。

我认为您要在此处使用的一般模式如下:

span :: (a -> Bool) -> [a] -> ([a], [a])
span pred [] = ([], [])
span pred (x:xs) = if pred x then _ else _  -- fill in the blanks
    where (prefix', suffix') = span pred xs

那里有两个不明显的东西。首先,注意 where 条件中的模式匹配。这意味着我们是:

  1. 调用span pred xs,生成一对列表;
  2. 这对的模式匹配;
  3. 分别命名对的第一个和第二个元素 prefix'suffix'

我怀疑第 2 步,即递归调用结果的模式匹配,您可能没有理解。

第二个不明显的事情是递归。这是一件棘手的事情,因为,与直觉相反,要用递归解决问题,您需要假设您已经解决了它,但是对于 "wrong" 论点——如果您还没有解决,想象自己采取的艰难步骤还没完成!但诀窍是:

  • 假设您实际上已经解决了问题,但是对于列表的 tail。这就是 prefix'suffix' 变量包含的内容:一个正确的解决方案,但对于错误的列表——您实际要解决的那个的尾部。
  • 鉴于该(非)解决方案,您如何重新使用它来为您的问题找到正确的解决方案?