Haskell - 需要帮助理解这个分裂函数

时间:2012-12-14 03:12:39

标签: haskell

我需要帮助理解以下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中,跟踪器函数在逐步评估表达式时非常有用,但不幸的是,GHCi没有这样的功能。请帮我逐步完成代码。谢谢!

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

2 个答案:

答案 0 :(得分: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]并返回它。

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

答案 1 :(得分:4)

仔细考虑foldl表达式产生的内容。当它通过列表时,它会累积一个元组(c, a)。此元组的第一个元素c始终是数字列表。 a是一个数字列表列表 - 恰好是您想要返回的列表。

获得新号码后,如果其号码与c中的号码相同,则将其添加到c。如果与<{1}}中的不同符号,则您将c全部放入c

最后,您会得到ac的最后一个值的元组。 a几乎完全是您想要的结果,除非它不完整:您需要向其添加a。所以表达式的最后是

c

获取(ll, rr) = split l splitc)的结果,并将a分配给c,将ll分配给{{1} }}。最后的答案只是a,最后附加rr