3

我需要帮助理解以下 Haskell 函数,

split l = rr++[ll]
            where
              split = foldl
                        ( \ (c,a) e ->
                               case c of
                                [] -> ([e],a)  
                                _ -> if e*(head c) < 0
                                     then ([e],a++[c])
                                     else (c++[e],a))
                        ([],[])
              (ll,rr) = split l

> split [1,2,3,-1,-2,7,4,-3,-5,-6,2,3]
[[1,2,3],[-1,-2],[7,4],[-3,-5,-6],[2,3]]

如上所示,它将具有相同符号的连续数字拆分为单独的列表。在 Scheme 中,tracer 函数对逐步评估表达式非常有帮助,但不幸的是,GHCi 没有这样的功能。请帮助我逐步完成代码。谢谢!

注意:我理解函数的 foldl 部分。真正让我困惑的是模式匹配部分(split l = rr++[ll]和)!(ll,rr) = split l

4

2 回答 2

8

我认为这里可能会让你感到困惑的是,实际上split内部实际上与顶层where完全不同——内部“遮蔽”了外部,就像局部变量覆盖全局变量一样。split下面的代码做同样的事情:

split l = rr++[ll]
            where
              notSplit = foldl
                        ( \ (c,a) e ->
                               case c of
                                [] -> ([e],a)  
                                _ -> if e*(head c) < 0
                                     then ([e],a++[c])
                                     else (c++[e],a))
                        ([],[])
              (ll,rr) = notSplit l

所以我们调用notSplit输入列表,它返回一个元组(ll,rr),然后我们计算rr ++ [ll]并返回它。

(正如我上面的评论所说,该算法在包括零的列表上是不必要的模糊、低效和不正确的。但这完全是另一个问题)。

于 2012-12-14T03:47:08.603 回答
4

想一想foldl表达式产生了什么。当它遍历列表时,它会累积一个 tuple (c, a)。这个元组的第一个元素 ,c总是一个数字列表。a是数字列表的列表——恰好是您想要返回的内容。

当你得到一个新数字时,如果它与 中的数字具有相同的符号,则将其c添加到 中c。如果它的符号与当前的符号不同c,则将其全部c放入a.

最后,你得到一个 和 的最后一个值的元caa几乎正是您想要的结果,只是它不完整:您需要添加c它。所以表达式的最后

(ll, rr) = split l

split(which is cand a) 的结果并赋值clland ato rrrr最后的答案只是ll附加到最后。

于 2012-12-14T03:49:21.673 回答