【问题标题】:Haskell - Need help understanding this split functionHaskell - 需要帮助理解这个拆分功能
【发布时间】:2012-12-14 03:12:38
【问题描述】:

我需要帮助理解以下 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)!

【问题讨论】:

  • 哪个模式匹配部分 - 你的意思是 case 表达式?有什么让你困惑的地方?
  • 我的意思是,算法本身非常令人困惑,而且,好吧,彻头彻尾的反常:) - 在以 0 开头的列表上尝试它。但你应该清楚它是那个还是语法或那个你被困住了。
  • 不管怎样,GHCi 可以进行追踪。不过,我现在不记得是怎么回事了……
  • 我理解 foldl 的 case 表达部分。 split l = rr++[ll] 和 (ll,rr) = split l 让我很困惑,谢谢! :) 是的,在别处问过,被告知这是错误的代码!
  • 我编辑了问题以在此处包含您的说明,希望您不介意(请随意使用不同的方法)

标签: haskell


【解决方案1】:

我认为这里可能会让您感到困惑的是,实际上where 内部的split 实际上与顶层的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]并返回它。

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

【讨论】:

  • 谢谢,我确实认为内部拆分与外部拆分相同。谢谢! :)
【解决方案2】:

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

当您获得一个新号码时,如果它与c 中的号码具有相同的符号,则将其添加到c。如果它的符号c 中当前的符号不同,则将所有c 放入a

最后,您会得到ca 的最后一个值的元组。 a 几乎就是您想要的结果,只是它不完整:您需要在其中添加 c。所以表达式的结尾

(ll, rr) = split l

获取split 的结果(即ca)并将c 分配给lla 分配给rr。最终的答案就是rr,并在末尾附加ll

【讨论】:

  • 你的解释很清楚!谢谢! :) 我会尽可能地支持你的答案。
猜你喜欢
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 2019-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-08
相关资源
最近更新 更多