【问题标题】:Easy way to break foldl打破折叠的简单方法
【发布时间】:2011-12-07 08:44:40
【问题描述】:

我需要摆脱 foldl。这是一个虚拟示例,当我计算列表中值的总和并遇到太大的值(即 10)时,如何从折叠中中断

   L = [1,2,3,4,10,5,6,7],

   Res = 
      try
         lists:foldl(
            fun(I, Value) ->
               if (I < 10) ->
                  Value + I;
               true ->
                  throw({too_big_value, Value})
               end
            end,
            0, L)
      catch
         throw:{too_big_value, Value} -> Value
      end,

   Res.

我知道这个例子是人为的,但是有什么好的方法可以打破折叠(我知道折叠总是扫描整个结构)?

请注意,即使我不折叠,我也需要检索正确的数据。在这种情况下,我应该从之前的迭代中获取数据(就像在我的示例中所做的那样)。

【问题讨论】:

  • “即使我从折叠中中断,我也需要检索正确的数据”是什么意思?您是否需要包含对投掷所做更改的列表?

标签: erlang fold


【解决方案1】:

只是好奇,在这里使用foldl 有什么意义?如果需要突围,使用递归,foldl 不是为它设计的。

main([]) ->
  L = [1,2,3,4,5,10,6,7],

   io:format("[~w]", [s(L, 0)]).

s([], S) ->
  S;

s([H|T], S) ->
  if (H < 10) ->
    s(T, S + H);
  true ->
    S
  end.

更新:

另一种选择是使用takewhile:

lists:foldl(fun(E, A) -> A + E end, 0, lists:takewhile(fun(E) -> E < 10 end, L))

【讨论】:

  • 感谢您的回复。我正在尝试找到获得更多可读代码的方法。我是 Erlang 的新手,我试图理解这是做某事的更好方法。我想你的第二个变种比我的和你的第一个更好。
  • @usr 只有第二个变体可能会创建额外的列表占用内存(除非编译器可以优化它),而第一个不会。
【解决方案2】:

你做得对,使用 try/catch 的 throw 进行非本地返回。如果函数从 fun 中查看返回值来决定是否继续,就不会是 foldl 了。

【讨论】:

  • 你能回答一个哲学问题吗:“如果不是为它设计的,就可以打破它吗?”什么是更好的选择:1)发明一些东西(打破折叠)2)编写更多代码(做递归)?
  • 我觉得没问题。 throw/catch 增加了很少的开销(肯定小于相应的类似折叠的函数,该函数将 continue-or-not 标志作为每个函数应用程序的结果的一部分),它清晰易读,并且您使用常见的习惯用法 ( foldl) 而不是编写自己的递归函数。
猜你喜欢
  • 2015-08-27
  • 2022-12-20
  • 2011-12-19
  • 2012-01-19
  • 1970-01-01
  • 2018-07-09
  • 2013-11-24
  • 1970-01-01
  • 2012-06-13
相关资源
最近更新 更多