【问题标题】:Rebinding variables in outer scopes in Elixir在 Elixir 的外部范围内重新绑定变量
【发布时间】:2016-03-14 01:17:50
【问题描述】:

我是函数式/不可变编程的新手,但我碰壁了。我正在尝试在Elixir 中实现一个非常简单的重复数据删除功能,以对stdin 进行重复数据删除。

我有一个使用 Stream.transform/2 的非常简单的实现,但我的原始实现使用了这样的 Stream.filter/2(为了举例目的,这被简化了),我不确定我是否理解它为什么不起作用:

hashes = HashSet.new

IO.stream(:stdio, :line)
  |> Stream.filter(fn(line) ->
      if HashSet.member?(hashes, line) do
        false
      else
        hashes = HashSet.put(hashes, line)
        true
      end
    end)
  |> Enum.each(&IO.write(&1))

这个想法显然是有一个 Set 包含读入的行,并且在每个循环中都会更新。

现在,一些调试使我发现filter 回调中的hashes 在每个循环中都是空的,所以我猜它没有更改外部变量?我相信我只想重新绑定外部的变量,而不是过滤器函数内部的变量。这可能吗?

我认为我遇到了这个 JavaScript 所证明的范围界定问题(这是我能想到的唯一比较):

var hashes = new Set();

arr.filter(function (element) {
    var hashes = something(element); // i.e. using var not using outer scope
});

任何人都可以确切地澄清上述实现的不正确之处吗?在此先感谢:)

【问题讨论】:

    标签: functional-programming elixir


    【解决方案1】:

    为什么不使用Stream.uniq/2 (uniq/2) 过滤掉所有重复的行

    IO.stream(:stdio, :line)
    |> Stream.uniq
    |> Enum.each(&IO.write(&1))
    

    【讨论】:

    • 这只是一个例子——如果我想根据每一行的一些值来解析和唯一呢?
    • 根据uniq/2 的文档,您可以传递一个函数作为第二个参数来提供唯一性标准,例如IO.stream(:stdio, :line) |> Stream.uniq(fn(x) -> String.length(x) end) |> Enum.each(&IO.write(&1))
    • 嗯,太棒了。我曾认为可能是这种情况,但它似乎从来没有为我工作过。也许我需要更新。
    【解决方案2】:

    来自https://elixir-lang.readthedocs.org/en/latest/technical/scoping.html#function-clause-scope

    每个函数子句都定义了一个新的词法范围:绑定在其中的任何新变量在该子句之外都将不可用

    由于 Elixir 中如何实现不变性和变量,因此在内部函数中分配给 hashes 与每次都绑定到一个新变量相同。

    【讨论】:

    • 所以没有办法在外部范围内重新绑定一些东西?我希望有办法手动完成。
    • 我不这么认为。但是,它也不是惯用的。您通常不会为副作用调用函数,而是为它们的返回值调用函数。通常你会使用 Enum 或 Stream 中的一些函数。 Stream.uniq/2 可以在这里工作,更一般地说,Enum.reduce/3 几乎可以做任何事情。
    • 原因是 Stream.filter 有并行实现,但 Stream.uniq 没有;)感谢您提供的信息。
    • 作为参考,请参阅 José 对此的回答:stackoverflow.com/questions/29924170/…
    猜你喜欢
    • 1970-01-01
    • 2021-08-18
    • 2017-12-02
    • 2015-11-03
    • 2019-10-05
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多