2016-12-03 78 views
2

大概一個非常基本的藥劑的問題時之外,功能沒有定義,返回一個匿名功能

我想從1至10,並輸出給IO.puts

第一總和的偶數我嘗試這樣做:

1..10 
|> Enum.filter(fn (x) -> rem(x, 2) == 0 end) 
|> Enum.sum 
|> IO.puts 

它按預期工作。


然後我嘗試界定功能的模塊裏面這樣:

defmodule Test do 
    def is_even(x) do 
    rem(x, 2) == 0 
    end 
end 

1..10 
|> Enum.filter(Test.is_even) 
|> Enum.sum 
|> IO.puts 

但是,這使我對編譯以下錯誤:

** (UndefinedFunctionError) undefined function: Test.is_even/0 
    Test.is_even() 
    tmp/src.exs:8: (file) 
    (elixir) src/elixir_lexical.erl:17: :elixir_lexical.run/3 
    (elixir) lib/code.ex:316: Code.require_file/2 

爲什麼找is_even/0當它應該(在我的意圖)尋找is_even/1?


我不明白這是爲什麼,特別是因爲這樣做:

defmodule Test do 
    def hello(x) do 
    IO.puts(x) 
    end 
end 

Test.hello("Hello World!") 

作品完全罰款。


我也只是發現了這個工程:

defmodule Test do 
    def is_even() do 
    fn (x) -> rem(x, 2) == 0 end 
    end 
end 

1..10 
|> Enum.filter(Test.is_even) 
|> Enum.sum 
|> IO.puts 

爲什麼使用它的函數的返回作爲函數的使用,而不是使用函數本身?

有沒有辦法讓這項工作,而不必返回函數內部的匿名函數?

回答

3

與一些常見語言不同,Elixir(和Erlang以及所有基於BEAM的語言)允許您定義具有相同名稱的多個函數。 Elixir會嘗試將函數調用與具有與您調用的相同元素的定義進行匹配。

Arity是一個函數所需的參數個數。例如,下面的函數具有0

def foo() do 
    IO.puts "foo" 
end 

而此函數

def bar(x) do 
    IO.puts "bar" 
end 

具有爲1的元數的元數,即使該論點是未使用的。

隨着你的模塊

defmodule Test do 
    def is_even(x) do 
    rem(x, 2) == 0 
    end 
end 

你用1

當你試着打電話給你的功能Test.is_even在鏈中的元數定義的函數is_even,你就叫它,如果它有一個arity爲0.如果你想指定你的函數預期爲arity 1,你可以使用下面的符號&Test.is_even/1。所以,你的榜樣將成爲

1..10 
|> Enum.filter(&Test.is_even/1) 
|> Enum.sum 
|> IO.puts 
1
defmodule Test do 
    def is_even(x) do 
    rem(x, 2) == 0 
    end 
end 

1..10 
|> Enum.filter(Test.is_even) 
|> Enum.sum 
|> IO.puts 

|> Enum.filter(Test.is_even)是不因爲如何管道操作符作品的工作就行了。管道運算符會將表達式的結果放在它之前(1..10)作爲Enum.filter/2的第一個參數,但它不會將它作爲Test.is_even/1的參數,因爲它位於filter之內。

該行類似於書寫:Enum.filter 1..10, Test.is_even(),沒有參數傳遞給Test.is_even,所以它尋找一個0-arity函數,但它找不到一個函數。

最後一個示例中的is_even/0工作原因是該函數返回的匿名函數與您給出的第一個示例相同。

+1

這解釋了爲什麼他們正在嘗試做是不行的,但不知道如何真正使其發揮作用。 –

+0

我回答了第一個問題。 –

1

是的,你想要做什麼是可能和容易的。你正在嘗試傳遞一個函數,就像在Elixir中的其他值一樣,這是可能的。例如:

f = &IO.puts/1 

此分配IO.puts/1到可變f,它可以像其他值被使用。每當引用一個像這樣的函數時,你必須包含函數的參數,在你的情況下它是1,因爲你的函數有一個參數。當調用函數時,arity是隱含的,因爲你傳遞了許多參數,但是當你以這種方式引用函數時,你必須手動指定參數,因爲可能有多個版本的is_even函數具有不同的arities,不知道你想要哪一個。

你的代碼應該是這樣的:

defmodule Test do 
    def is_even(x) do 
    rem(x, 2) == 0 
    end 
end 

1..10 
|> Enum.filter(&Test.is_even/1) 
|> Enum.sum 
|> IO.puts