1. ホーム
  2. scala

[解決済み] Scalaの複数パラメータリストと複数パラメータ/リストの違いは何ですか?

2023-05-18 12:44:31

質問

Scalaでは、次のような(curried?)関数を書くことができます。

def curriedFunc(arg1: Int) (arg2: String) = { ... }

上記の curriedFunc という関数定義と、1つのパラメータリストに複数のパラメータを持つ関数の違いは何ですか?

def curriedFunc(arg1: Int, arg2: String) = { ... }

数学的な観点からは、これは (curriedFunc(x))(y) であり curriedFunc(x,y) と書くことができますが def sum(x) (y) = x + y と書くと、同じように def sum2(x, y) = x + y

私は1つだけ違いを知っています - これは部分的に適用された関数です。しかし、両方の方法は私にとっては等価です。

他に違いはありますか?

どのように解決するのですか?

厳密に言えば、これは curried 関数ではなく、複数の引数リストを持つメソッドですが、たしかに関数のように見えます。

あなたが言ったように、複数の引数リストによって、部分的に適用された関数の代わりにこのメソッドを使用することができます。(私が使う一般的に愚かな例で申し訳ありません)

object NonCurr {
  def tabulate[A](n: Int, fun: Int => A) = IndexedSeq.tabulate(n)(fun)
}

NonCurr.tabulate[Double](10, _)            // not possible
val x = IndexedSeq.tabulate[Double](10) _  // possible. x is Function1 now
x(math.exp(_))                             // complete the application

もう一つの利点は、括弧の代わりに中括弧を使えることで、第2引数リストが単一の関数、またはサンクから構成されている場合に見栄えが良くなることです。例えば

NonCurr.tabulate(10, { i => val j = util.Random.nextInt(i + 1); i - i % 2 })

IndexedSeq.tabulate(10) { i =>
  val j = util.Random.nextInt(i + 1)
  i - i % 2
}

サンクの場合も

IndexedSeq.fill(10) {
  println("debug: operating the random number generator")
  util.Random.nextInt(99)
}

もう一つの利点は、前の引数リストの引数を参照してデフォルトの引数値を定義できることです(シングルリストでそれができないのは欠点とも言えますが :)。

// again I'm not very creative with the example, so forgive me
def doSomething(f: java.io.File)(modDate: Long = f.lastModified) = ???

最後に、関連する投稿への回答で、他の3つのアプリケーションがあります。 なぜScalaは複数のパラメータリストとリストごとの複数のパラメータの両方を提供するのですか? . ここではそれらをコピーするだけですが,謝辞は Knut Arne Vedaa,Kevin Wright,extempore に捧げます.

第一に、複数の var args を持つことができます。

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

...これは、単一の引数リストでは不可能でしょう。

第二に、型推論を補助するものです。

def foo[T](a: T, b: T)(op: (T,T) => T) = op(a, b)
foo(1, 2){_ + _}   // compiler can infer the type of the op function

def foo2[T](a: T, b: T, op: (T,T) => T) = op(a, b)
foo2(1, 2, _ + _)  // compiler too stupid, unfortunately

そして最後に、これは暗黙の引数と非暗黙の引数を持つように implicit は引数リスト全体に対するモディファイアだからです。

def gaga [A](x: A)(implicit mf: Manifest[A]) = ???   // ok
def gaga2[A](x: A, implicit mf: Manifest[A]) = ???   // not possible