web-dev-qa-db-ja.com

Scalaが複数のパラメーターリストとリストごとの複数のパラメーターの両方を提供するのはなぜですか?

複数のパラメーターリスト、たとえばdef foo(a:Int)(b:Int) = {}およびリストごとの複数のパラメーター。 def foo(a:Int, b:Int) = {}は、私の知る限り意味的に同等であり、ほとんどの関数型言語は、複数のパラメーターを宣言する1つの方法しか持っていません。 F#。

これらの両方のスタイルの関数定義をサポートする理由は、1つのパラメーターのみを含むパラメーターリストを使用して、構文のような言語拡張を許可するためです。

def withBufferedWriter(file: File)(block: BufferedWriter => Unit)

構文のように見えるようになりました

withBufferedWriter(new File("myfile.txt")) { out =>
  out write "whatever"
  ...
}

ただし、複数のパラメーターリストを持たずに中かっこの使用をサポートする他の方法があります。

関連する質問:なぜScala "currying"と呼ばれる複数のパラメーターリストを使用するのですか?カリー化は、通常、部分適用をサポートするためにn項関数を単項にするための手法として定義されますただし、Scalaでは、関数の「カリー化」(各パラメーターが1つの複数のパラメーターリスト)バージョンを作成せずに、関数を部分的に適用できます。

78
Yuvi Masory

次のことができるようになります:

scala> def foo(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum
foo: (as: Int*)(bs: Int*)(cs: Int*)Int

scala> foo(1, 2, 3)(4, 5, 6, 7, 9)(10, 11)
res7: Int = 3906
76
Knut Arne Vedaa

言語の一部のように見えるメソッド(すでに見つけたもの)を作成できるようにするだけでなく、型推論器が一度に1つのブロックで機能することに注意してください。

これで:

def foo[T](a: T, b: T)(op: (T,T)=>T) = op(a,b)
foo(1,2){_+_}

Tは最初にIntとして推論され、クロージャー内の2つのアンダースコアの型として使用されます。これにより、コンパイラは、完全な型安全性を備えた+演算が有効であることを認識します。

45
Kevin Wright

「関連する質問」に答えるために、カリー化は、複数の引数の関数、たとえば_(A, B, C) => D_を、1つの引数を取り関数を返す関数に変換する方法です。 A => (B => (C => D))(括弧は表示されていますが、必須ではありません)。

タプル化された形式とカリー化された形式は同型であり、それらの間で自由に翻訳できます。これらはすべて同等ですが、構文上の意味が異なります。

_(A, B, C, D, E) => F
((A, B), (C, D, E)) => F
(A, B) => (C, D, E) => F
_

個別のパラメーターグループを宣言するとき、これは実行している種類のカレーです。 multi-parameter-groupメソッドは関数を返すメソッドです...これはREPLで見ることができます:

_scala> def foo(a:Int, b:Int)(c:Int, d:Int, e:Int):Int = 9
foo: (a: Int,b: Int)(c: Int,d: Int,e: Int)Int

scala> foo _                                             
res4: (Int, Int) => (Int, Int, Int) => Int = <function2>
_
24
Tom Crockett

デフォルト引数の後方参照:

case class Foo(bar: Int)

def test(f: Foo)(i: Int = f.bar) = i*i

test(Foo(3))()
21
0__

動機の1つが暗黙的なパラメーターリストだったことを知っています。 「暗黙的」はリストのプロパティであり、パラメータではありません。もう1つはおそらくケースクラスでした。最初のパラメーターリストのみがケースフィールドになります。

12
psp