2012-12-10 8 views
6

に私の同僚をカリー化実行高階関数を実装:は、次のように私に質問を送ったScalaの

は、あなたの関数の 署名がようである、カリー化を行い、HOF(高階関数)を実装します次の次のよう

def curry[A,B,C](f:(A,B) => C) : A => B => C 
同様

は、uncurrying行う機能を実装:

def uncurry[A,B,C](f:A => B => C): (A,B) => C 

私はカリー化を理解する方法を使用すると、複数のパラメータを取る機能を持っている場合は、結果を得るまで、あなたが繰り返しPARAMATERSのそれぞれに関数を適用することができるということです。

したがって、f:(A,B) => Cの行に沿ったものはA => f(A,_) => f(B)になりますか?

そしてuncurryingは、次のように一つの関数の中に、このアプリケーションを統合するために、次のようになります。

f:A=>B=>Cf(A,B)でしょうか?

多分私はここの構文で混乱しているかもしれませんが、もし誰かが私がここで紛失していることを指摘できれば素晴らしいでしょう。何を知りたいのですが、実際の実装のほかに -

おかげ

答えて

12

たくさんのコメントを付けて、この完全に機能した例を理解してください。ご不明な点がございましたら、ご返信ください。

このコードは、Scalaインタプリタにドロップすることで実行できます。

// Here's a trait encapsulating the definition your coworker sent. 
trait Given { 
    def curry[A,B,C](f:(A,B) => C) : A => B => C 
    def uncurry[A,B,C](f:A => B => C): (A,B) => C 
} 

object Impl extends Given { 
    // I'm going to implement uncurry first because it's the easier of the 
    // two to understand. The bit in curly braces after the equal sign is a 
    // function literal which takes two arguments and applies the to (i.e. 
    // uses it as the arguments for) a function which returns a function. 
    // It then passes the second argument to the returned function. 
    // Finally it returns the value of the second function. 
    def uncurry[A,B,C](f:A => B => C): (A,B) => C = { (a: A, b: B) => f(a)(b) } 

    // The bit in curly braces after the equal sign is a function literal 
    // which takes one argument and returns a new function. I.e., curry() 
    // returns a function which when called returns another function 
    def curry[A,B,C](f:(A,B) => C) : A => B => C = { (a: A) => { (b: B) => f(a,b) } } 
} 

def add(a: Int, b: Long): Double = a.toDouble + b 
val spicyAdd = Impl.curry(add) 
println(spicyAdd(1)(2L)) // prints "3.0" 
val increment = spicyAdd(1) // increment holds a function which takes a long and adds 1 to it. 
println(increment(1L)) // prints "2.0" 
val unspicedAdd = Impl.uncurry(spicyAdd) 
println(unspicedAdd(4, 5L)) // prints "9.0" 

数値の小さい例はどうですか。

def log(level: String, message: String) { 
    println("%s: %s".format(level, message)) 
} 
val spicyLog = Impl.curry(log) // spicyLog's type is String => Unit 
val logDebug = spicyLog("debug") // This new function will always prefix the log 
           // message with "debug". 
val logWarn = spicyLog("warn") // This new function will always prefix the log 
           // message with "warn". 
logDebug("Hi, sc_ray!") // prints "debug: Hi, sc_ray!" 
logWarn("Something is wrong.") // prints "warn: Something is wrong." 

更新 あなたは求めて答えた、「コンパイラは、このようなa => b => f(a,b)として式を評価しない方法。」まあそれはしません。少なくとも、あなたの同僚のスニペットで定義されているものはコンパイルされません。しかし、一般的には、A => B => Cという形式の何かを見ると、「Aを引数にとり、Bを引数にとり、Cを返す関数を返します。

+0

説明をありがとう。これは非常に実用的な例です。コンパイラがa => b => f(a、b)のような式をどのように評価するかを考えようと全部混乱しているだけです。 –

+0

私はアップデートを投稿しました。それが役立つかどうか私に教えてください。 –

+0

ありがとうございます。今ははるかに明確です。私はこれを答えとしてマークしています。 –

8

は、私は本当にあなたの質問を理解していませんか?説明したように、それは非常に些細なことする必要があります「、返り値を再びあるb => f(a,b)ある引数、a、引数、bの機能の関数である

def curry[A,B,C](f:(A,B) => C): A => B => C = 
    a => b => f(a,b) 

a => b => f(a,b)手段あなたの得意先の戻り値を返しますf(a,b)(タイプがC) "

a => b => f(a, b)これは助けば少し冗長に書くことができますか?

{ (a: A) => {   // a function of *one* argument, `a` 
     (b: B) => {  // a function of *one* argument, `b` 
     f(a, b)   // whose return value is what you get of you execute `f(a,b)` (whose type is `C`) 
     } 
    } 
} 

(a, b) => f(a)(b)手段、「戻り値あなたが最初の関数を返すHOF faを適用すると、あなたが得るものです引数(a, b)の機能それはbを返してC "を返します。

これは役に立ちますか?

+0

=> b => f(a、b)と入力すると、正確に何が起こるのか知りたかったと思いますか? –

+0

@sc_ray追加の説明が役立つことを願っていますか? – Faiz

+1

あなたの説明をありがとう。私はこのトリプルではないカリングの全体概念を見出しているので、複数のパラメータを持つ関数があり、関数をa => b => f(a、b)という関数に書き換えることで、関数の実行を一度にパラメータの実行を延期します。 )?コンパイラはa => b => f(a、b)のような式をどのように評価しますか? –

関連する問題