2015-12-08 19 views
2

我是功能/不可变编程的新手,我碰到了一堵墙。我试图在Elixir中实现一个非常简单的重复数据删除功能,以重复数据删除stdin在Elixir的外部范围中重新绑定变量

我有使用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)) 

的想法显然是有一个包含读入的行,并在每个循环更新。

现在,一些调试导致我的事实hashes里面的filter回调在每个循环中都是空的,所以我猜它不会改变外层变量?我相信我只是想在外部重新绑定变量,而不是滤波函数中的变量。这可能吗?

我在想,我打一个范围问题,这个JavaScript作为证明(这是我能想到的唯一的比较):

var hashes = new Set(); 

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

任何人都可以清楚地了解到是不正确上述实施?感谢提前:)

回答

5

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

每个功能的语句定义了一个新的词汇范围:任何新其内部的变量绑定将不会在该子句之外提供

Bec在Elixir中如何实现不变性和变量,在内部函数中赋值hashes与每次绑定一个新变量相同。

+0

所以没有办法在外部范围重新绑定某些东西?我希望可能有办法手动这样做。 – whitfin

+1

我认为不是。然而,这也不是惯用的。你通常不会为副作用调用函数,而是为它们的返回值。通常你使用Enum或Stream的一些函数。 'Stream.uniq/2'可以在这里和更一般的情况下工作,'Enum.reduce/3'可以做任何事情。 – manukall

+0

原因是有Stream.filter的并行实现,但Stream.uniq没有;)谢谢你的信息。 – whitfin

0

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

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

这只是一个例子 - 如果我想根据每行上的某些值进行解析和唯一性分析,该怎么办? – whitfin

+0

根据''uniq/2''的文档,你可以传递一个函数作为第二个参数来提供唯一性标准,例如IO.stream(:stdio,:line)|> Stream.uniq(fn( x) - > String.length(x)end)|> Enum.each(&IO.write(&1))'' – 0x0me

+0

好吧,那太棒了。我曾认为可能是这样,但它似乎从来没有为我工作。也许我需要更新。 – whitfin