2016-07-12 6 views
1

私はエリクシールのexampleでこのコードを参照してください。同じ名前を持つ関数が、関数型言語で異なる引数

defmodule Recursion do 
    def print_multiple_times(msg, n) when n <= 1 do 
    IO.puts msg 
    end 

    def print_multiple_times(msg, n) do 
    IO.puts msg 
    print_multiple_times(msg, n - 1) 
    end 
end 

Recursion.print_multiple_times("Hello!", 3) 

私はここに異なる引数で二回定義された同じ機能見て、私はこのテクニックを理解したいです。

オーバーロードされた機能のように見えますか?

異なる動作を持つ単一の関数か、print_only_onceprint_multiple_timesのような2つの異なる関数ですか?

これらの機能はどうにかしてリンクされていますか?

+1

これは本当に*パターンマッチング*とガード句です。 'when'ガード節の評価を含む、引数に最も適合する*関数の実装*が選択されます。これは同じ機能ですが、複数の実装しかありません。 – deceze

+2

あなたの関数は異なる署名を持っていますが、大丈夫ですが、署名が同じであれば別のアクセス(defまたはdefp)は許されません。 – PatNowak

答えて

4

通常、関数型言語では、関数は節で定義されます。例えば、命令型言語でフィボナッチを実装する1つの方法は、次のコード(ない最高の実装)のようになります。

def fibonacci(n): 
    if n < 0: 
    return None 
    if n == 0 or n == 1: 
    return 1 
    else: 
    return fibonacci(n - 1) + fibonacci(n - 2) 

あなたが次のことを行うだろうエリクサーで関数を定義するには:

defmodule Test do 
    def fibonacci(0), do: 1 
    def fibonacci(1), do: 1 
    def fibonacci(n) when n > 1 do 
    fibonacci(n-1) + fibonacci(n - 2) 
    end 
    def fibonacci(_), do: nil 
end 

Test.fibonacci/1は1つの機能に過ぎません。数が0

  • 場合にのみ1

    • の4節とアリティを持つ関数は、最初の句は、数が第三の句は、いずれかと一致1
    • 場合にのみ第二句が一致一致します
    • 最後の節は何でも一致します(_は、変数の値が節内で使用されない場合、または一致するものではない場合に使用されます)。 Test.fibonacci(2)するための第1の2節に失敗し2 > 1ため、第三のものと一致して

    句は、それらが宣言された順序で評価されています。

    節をより強力なifと考えてください。コードはこのようにきれいに見えます。また、再帰には非常に便利です。例えば、マップの実装(言語はすでにEnum.map/2の1を提供):

    defmodule Test do 
        def map([], _), do: [] 
        def map([x | xs], f) when is_function(f) do 
        [f.(x) | map(xs, f)] 
        end 
    end 
    
    • まず句は、空のリストと一致します。機能を適用する必要はありません。
    • 第2節は、最初の要素(先頭)がxであり、残りのリスト(末尾)がxsで、fが関数であるリストと一致します。最初の要素に関数を適用し、リストの残りの部分と再帰的にmapを呼び出します。

    Test.map([1,2,3], fn x -> x * 2 end)を呼び出すと、あなたの次の出力[2, 4, 6]

    ので、エリクシール内の関数は、すべての節が他の部分と同じアリティを有する1つまたは複数の条項で定義されたを与えるだろう。

    これがあなたの質問に答えることを願っています。

  • +1

    ほんの少しのコメント: "通常、関数型言語では関数は句で定義されます。"これはHaskellとStandard MLでは当てはまりますが、例えばOCamlやSchemeではそうではありません。 – FPstudent

    1

    あなたが投稿した例では、関数の両方の定義に同じ数の引数があります:2、この「時」はガードですが、多くの引数を持つ定義を持つこともできます。まず、警備員 - 彼らは、次の2行目のように、単なるマッチングのように書くことができないものを表現するために使用されている: - それはちょうど平等/マッチングでいる負の数を表現することはできませんので、

    def fac(0), do: 1 
    def fac(n), when n<0 do: "no factorial for negative numbers!" 
    def fac(n), do: n*fac(n-1) 
    

    btwこのファシリティは、3つのケースでのみ定義されています。さえにかなり近い見えます

    def fac(n) do 
        if n==0, do: 1, else: if n<0, do: "no factorial!", else: n*fac(n-1) 
    end 
    

    またはスイッチケース(:あなたはそれがよりよい書き込むための方法だろうと考えることができ、引数:) の位置にある定数「0」を使用しての涼しさに注目してください上記):

    def fa(n) do 
        case n do 
        0 -> 1 
        n when n>0 -> n*fa(n-1) 
        _ -> "no no no" 
        end 
    end 
    

    「もっと見栄えが良い」実際には、後者のスタイルよりもはるかに良く見える特定の定義(パーサ、小さな通訳など)が判明しています。 Nbガードの表現は非常に限られています(あなた自身の関数をガードに使うことはできません)。

    実際のところ、さまざまな議論があります - これをチェックしてください!

    def mutant(a), do: a*a 
    def mutant(a,b), do: a*b 
    def mutant(a,b,c), do: mutant(a,b)+mutant(c) 
    

    iex(1)> Lol.mutant(2) 
    4 
    iex(2)> Lol.mutant(2,3) 
    6 
    iex(3)> Lol.mutant(2,3,4) 
    22 
    

    それはスキーム中(ラムダ引数...)のような類似したビットで動作します - それ以上のリストと一致するように、すべての引数を取るよう変異を考えます。しかし今回、エリキシルは突然変異体を3つの機能、すなわち突然変異体/ 1,突然変異体/ 2および突然変異体/ 3として扱い、これらを参照する。

    あなたの質問に答えてください:これらはオーバーロードされた関数ではなく、散在した/断片化された定義です。あなたはmiranda、haskell、smlのような関数型言語で同様のものを参照してください。

    関連する問題