2015-12-08 17 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