Example5.2

「Example5.2」の編集履歴(バックアップ)一覧はこちら

Example5.2」の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

#co(){ 5.2 Currying The latest formulation of the summing functions is already quite compact. But we can do even better. Note that a and b appear as parameters and arguments of every function but they do not seem to take part in interesting combinations. Is there a way to get rid of them? Let's try to rewrite sum so that it does not take the bounds a and b as parameters: } ** 5.2 カリー化 (Curring) 和を求める関数の最後の設計はすでにかなり簡潔です。しかし更に可能です。a と b がすべての関数で仮引数または実引数として現れる一方で、興味深い組み合わせを成していないようです。それらを除去できるでしょうか。 sum を書き直し、境界 a と b を引数にしないようにしましょう。 def sum(f: Int => Int): (Int, Int) => Int = { def sumF(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sumF(a + 1, b) sumF } #co(){ In this formulation, sum is a function which returns another function, namely the specialized summing function sumF. This latter function does all the work; it takes the bounds a and b as parameters, applies sum's function parameter f to all integers between them, and sums up the results. Using this new formulation of sum, we can now define: } この設計では、sum は他の関数、すなわち特別な和を求める関数 sumF を返す関数です。後者の関数がすべての仕事をします。境界 a と b を引数としてとり、sum 関数の引数 f をその間のすべての整数に適用し、結果を足し合わせます。 新設計の sum を使って、次のように定義できます。 def sumInts = sum(x => x) def sumSquares = sum(x => x * x) def sumPowersOfTwo = sum(powerOfTwo) Or, equivalently, with value definitions: あるいは同等に、値定義を使って val sumInts = sum(x => x) val sumSquares = sum(x => x * x) val sumPowersOfTwo = sum(powerOfTwo) #co(){ sumInts, sumSquares, and sumPowersOfTwo can be applied like any other function. For instance, } sumInts, sumSquares, sumPowersOfTwo は、他の関数と同じように適用できます。たとえば scala> sumSquares(1, 10) + sumPowersOfTwo(10, 20) unnamed0: Int = 267632001 #co(){ How are function-returning functions applied? As an example, in the expression } 関数を返す関数はどのように適用されるのでしょうか?例として式 sum(x => x * x)(1, 10) , #co(){ the function sum is applied to the squaring function (x => x * x). The resulting function is then applied to the second argument list, (1, 10). This notation is possible because function application associates to the left. That is, if args and argsare argument lists, then f(args 1)(args2) is equivalent to (f(args1 ))(args2) In our example, sum(x => x * x)(1, 10) is equivalent to the following expression: (sum(x => x * x))(1, 10). } の関数 sum は2乗する関数 (x => x * x) に適用されます。そして結果の関数は二番目の引数リスト (1, 10) に適用されます。 関数適用が左結合のため、この記法が可能です。すなわち、もし args1 と args2 が引数リストなら、 f(args 1)(args2) は (f(args1))(args2) と等価です。 この例では sum(x => x * x)(1, 10) は、式 (sum(x => x * x))(1, 10) と等価です。 #co(){ The style of function-returning functions is so useful that Scala has special syntax for it. For instance, the next definition of sum is equivalent to the previous one, but is shorter: } 関数を返す関数のスタイルはたいへん有用なので、Scala にはそのための特別な構文があります。たとえば次の sum 定義は前のものと等価ですが短くなっています。 def sum(f: Int => Int)(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sum(f)(a + 1, b) #co(){ Generally, a curried function definition } 一般に、カリー化された関数定義 def f (args1) ... (argsn) = E #co(){ where n > 1 expands to } ただし n>1、は次のように展開されます。 def f (args1) ... (argsn−1) = { def g (argsn) = E ; g } #co(){ where g is a fresh identifier. Or, shorter, using an anonymous function: } ただし g は未使用の識別子です。あるいはもっと短く無名関数を使って def f (args1) ... (argsn−1) = ( argsn) => E . #co(){ Performing this step n times yields that } このステップを n 回繰り返すと次を得ます。 def f (args1) ... (argsn) = E #co(){ is equivalent to } これは次と等価です。 def f = (args1) => ... => (argsn) => E . #co(){ Or, equivalently, using a value definition: } あるいは同様に値定義を用いて val f = (args) => ... => (args) => E . #co(){ This style of function definition and application is called currying after its promoter, Haskell B. Curry, a logician of the 20th century, even though the idea goes back further to Moses Schönfinkel and Gottlob Frege. The type of a function-returning function is expressed analogously to its parameter list. Taking the last formulation of sum as an example, the type of sum is (Int => Int) => (Int, Int) => Int. This is possible because function types associate to the right. I.e. T1 => T2 => T3 is equivalent to T1 => (T2 => T3) Exercise 5.2.1 1. The sum function uses a linear recursion. Can you write a tail-recursive one by filling in the ??'s? } この関数定義と適用のスタイルは、創始者である20世紀の論理学者 Haskell B. Curry に因んで&bold(){カリー化}と呼ばれています。しかしそのアイデアは Moses Schoenfinkel や Gottlob Frege にまで遡ります。 関数を返す関数の型は、引数リストに似た形で表されます。例として sum の最後の設計を見ると、sum の型は (Int => Int) => (Int, Int) => Int です。関数型は右結合なため、これが可能です。すなわち T1 => T2 => T3 は T1 => (T2 => T3) と等価 &b(){演習 5.2.1 } 関数 sum は線形再帰を使ってます。?? の部分を埋めて末尾再帰に書けますか? def sum(f: Int => Double)(a: Int, b: Int): Double = { def iter(a, result) = { if (??) ?? else iter(??, ??) } iter(??, ??) } #co(){ Exercise 5.2.2 Write a function product that computes the product of the values of functions at points over a given range. Exercise 5.2.3 Write factorial in terms of product. Exercise 5.2.4 Can you write an even more general function which generalizes both sum and product? } &b(){演習 5.2.2 } 与えられた範囲の点の、関数値の積を求める関数 product を書きなさい。 &b(){演習 5.2.3 } factorial を product を用いて書きなさい。 &b(){演習 5.2.4 } sum と product の両方を一般化する、より汎用的な関数を書けますか? #center(){[[前ページ>Example5.1]] [[ 5 章>ExampleChap5]] [[目次>ScalaByExample和訳]] [[次ページ>Example5.3]]} ---- - 翻訳ありがとうございます。翻訳とは直接関係ないのですが、def sumInts = sum(x => x) _ を定義すると、「_ must follow method; cannot follow (Int, Int) => Int」とエラーが出ます。なぜなのでしょうか? -- Gen (2008-08-24 15:33:28) - すいません。↑の投稿をしたものですが、def sumInts(x:Int, y:Int) = sum(x => x)(x, y)とすることで、実行可能になりました。お騒がせしました。 -- Gen (2008-08-24 15:42:44) #comment
#co(){ 5.2 Currying The latest formulation of the summing functions is already quite compact. But we can do even better. Note that a and b appear as parameters and arguments of every function but they do not seem to take part in interesting combinations. Is there a way to get rid of them? Let's try to rewrite sum so that it does not take the bounds a and b as parameters: } #setmenu2(ex-r-menu) ** 5.2 カリー化 (Curring) 和を求める関数の最後の設計はすでにかなり簡潔です。しかし更に可能です。a と b がすべての関数でパラメータまたは引数として現れる一方で、興味深い組み合わせを成していないようです。それらを除去できるでしょうか。 sum を書き直し、境界 a と b をパラメータにしないようにしましょう。 def sum(f: Int => Int): (Int, Int) => Int = { def sumF(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sumF(a + 1, b) sumF } #co(){ In this formulation, sum is a function which returns another function, namely the specialized summing function sumF. This latter function does all the work; it takes the bounds a and b as parameters, applies sum's function parameter f to all integers between them, and sums up the results. Using this new formulation of sum, we can now define: } この設計では、sum は他の関数、すなわち特別な和を求める関数 sumF を返す関数です。後者の関数がすべての仕事をします。境界 a と b をパラメータとしてとり、sum 関数のパラメータ f をその間のすべての整数に適用し、結果を足し合わせます。 新設計の sum を使って、次のように定義できます。 def sumInts = sum(x => x) def sumSquares = sum(x => x * x) def sumPowersOfTwo = sum(powerOfTwo) Or, equivalently, with value definitions: あるいは同等に、値定義を使って val sumInts = sum(x => x) val sumSquares = sum(x => x * x) val sumPowersOfTwo = sum(powerOfTwo) #co(){ sumInts, sumSquares, and sumPowersOfTwo can be applied like any other function. For instance, } sumInts, sumSquares, sumPowersOfTwo は、他の関数と同じように適用できます。たとえば scala> sumSquares(1, 10) + sumPowersOfTwo(10, 20) unnamed0: Int = 267632001 #co(){ How are function-returning functions applied? As an example, in the expression } 関数を返す関数はどのように適用されるのでしょうか?例として式 sum(x => x * x)(1, 10) , #co(){ the function sum is applied to the squaring function (x => x * x). The resulting function is then applied to the second argument list, (1, 10). This notation is possible because function application associates to the left. That is, if args and argsare argument lists, then f(args 1)(args2) is equivalent to (f(args1 ))(args2) In our example, sum(x => x * x)(1, 10) is equivalent to the following expression: (sum(x => x * x))(1, 10). } の関数 sum は2乗する関数 (x => x * x) に適用されます。そして結果の関数は二番目の引数リスト (1, 10) に適用されます。 関数適用が左結合のため、この記法が可能です。すなわち、もし args1 と args2 が引数リストなら、 f(args 1)(args2) は (f(args1))(args2) と等価です。 この例では sum(x => x * x)(1, 10) は、式 (sum(x => x * x))(1, 10) と等価です。 #co(){ The style of function-returning functions is so useful that Scala has special syntax for it. For instance, the next definition of sum is equivalent to the previous one, but is shorter: } 関数を返す関数のスタイルはたいへん有用なので、Scala にはそのための特別な構文があります。たとえば次の sum 定義は前のものと等価ですが短くなっています。 def sum(f: Int => Int)(a: Int, b: Int): Int = if (a > b) 0 else f(a) + sum(f)(a + 1, b) #co(){ Generally, a curried function definition } 一般に、カリー化された関数定義 def f (args1) ... (argsn) = E #co(){ where n > 1 expands to } ただし n>1、は次のように展開されます。 def f (args1) ... (argsn−1) = { def g (argsn) = E ; g } #co(){ where g is a fresh identifier. Or, shorter, using an anonymous function: } ただし g は未使用の識別子です。あるいはもっと短く無名関数を使って def f (args1) ... (argsn−1) = ( argsn) => E . #co(){ Performing this step n times yields that } このステップを n 回繰り返すと次を得ます。 def f (args1) ... (argsn) = E #co(){ is equivalent to } これは次と等価です。 def f = (args1) => ... => (argsn) => E . #co(){ Or, equivalently, using a value definition: } あるいは同様に値定義を用いて val f = (args) => ... => (args) => E . #co(){ This style of function definition and application is called currying after its promoter, Haskell B. Curry, a logician of the 20th century, even though the idea goes back further to Moses Schönfinkel and Gottlob Frege. The type of a function-returning function is expressed analogously to its parameter list. Taking the last formulation of sum as an example, the type of sum is (Int => Int) => (Int, Int) => Int. This is possible because function types associate to the right. I.e. T1 => T2 => T3 is equivalent to T1 => (T2 => T3) Exercise 5.2.1 1. The sum function uses a linear recursion. Can you write a tail-recursive one by filling in the ??'s? } この関数定義と適用のスタイルは、創始者である20世紀の論理学者 Haskell B. Curry に因んで&bold(){カリー化}と呼ばれています。しかしそのアイデアは Moses Schoenfinkel や Gottlob Frege にまで遡ります。 関数を返す関数の型は、パラメータリストに似た形で表されます。例として sum の最後の設計を見ると、sum の型は (Int => Int) => (Int, Int) => Int です。関数型は右結合なため、これが可能です。すなわち T1 => T2 => T3 は T1 => (T2 => T3) と等価 &b(){演習 5.2.1 } 関数 sum は線形再帰を使ってます。?? の部分を埋めて末尾再帰に書けますか? def sum(f: Int => Double)(a: Int, b: Int): Double = { def iter(a, result) = { if (??) ?? else iter(??, ??) } iter(??, ??) } #co(){ Exercise 5.2.2 Write a function product that computes the product of the values of functions at points over a given range. Exercise 5.2.3 Write factorial in terms of product. Exercise 5.2.4 Can you write an even more general function which generalizes both sum and product? } &b(){演習 5.2.2 } 与えられた範囲の点の、関数値の積を求める関数 product を書きなさい。 &b(){演習 5.2.3 } factorial を product を用いて書きなさい。 &b(){演習 5.2.4 } sum と product の両方を一般化する、より汎用的な関数を書けますか? #center(){[[前ページ>Example5.1]] [[ 5 章>ExampleChap5]] [[目次>ScalaByExample和訳]] [[次ページ>Example5.3]]} ---- - 翻訳ありがとうございます。翻訳とは直接関係ないのですが、def sumInts = sum(x => x) _ を定義すると、「_ must follow method; cannot follow (Int, Int) => Int」とエラーが出ます。なぜなのでしょうか? -- Gen (2008-08-24 15:33:28) - すいません。↑の投稿をしたものですが、def sumInts(x:Int, y:Int) = sum(x => x)(x, y)とすることで、実行可能になりました。お騒がせしました。 -- Gen (2008-08-24 15:42:44) #comment

表示オプション

横に並べて表示:
変化行の前後のみ表示:
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。