我需要帮助理解以下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
)让我感到困惑!
答案 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
。
最后,您会得到a
和c
的最后一个值的元组。 a
几乎完全是您想要的结果,除非它不完整:您需要向其添加a
。所以表达式的最后是
c
获取(ll, rr) = split l
(split
和c
)的结果,并将a
分配给c
,将ll
分配给{{1} }}。最后的答案只是a
,最后附加rr
。