Pertanyaan Apa perbedaan antara beberapa daftar parameter dan beberapa parameter per daftar di Scala?


Di Scala seseorang dapat menulis (curried?) Fungsi seperti ini

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

Apa bedanya di atas curriedFunc definisi fungsi dengan dua daftar parameter dan fungsi dengan beberapa parameter dalam daftar parameter tunggal:

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

Dari sudut pandang matematis inilah (curriedFunc(x))(y) dan curriedFunc(x,y) tapi saya bisa menulis def sum(x) (y) = x + y dan hal yang sama akan terjadi def sum2(x, y) = x + y

Saya hanya tahu satu perbedaan - ini adalah fungsi yang diterapkan sebagian. Tetapi kedua cara itu setara untuk saya.

Apakah ada perbedaan lain?


76
2017-07-23 20:48


asal


Jawaban:


Sebenarnya, ini bukan fungsi kari, tetapi metode dengan daftar argumen ganda, meskipun diakui itu tampak seperti sebuah fungsi.

Seperti yang Anda katakan, daftar argumen ganda memungkinkan metode yang akan digunakan di tempat fungsi yang diterapkan sebagian. (Maaf untuk contoh-contoh konyol yang biasa saya gunakan)

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

Manfaat lain adalah bahwa Anda dapat menggunakan kurung kurawal bukan kurung yang terlihat bagus jika daftar argumen kedua terdiri dari satu fungsi, atau thunk. Misalnya.

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

melawan

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

Atau untuk thunk:

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

Keuntungan lainnya adalah, Anda dapat merujuk ke argumen daftar argumen sebelumnya untuk menentukan nilai argumen default (meskipun Anda juga bisa mengatakan itu kerugian yang Anda tidak dapat melakukannya dalam daftar tunggal :)

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

Akhirnya, ada tiga aplikasi lain dalam jawaban untuk posting terkait Mengapa Scala menyediakan daftar beberapa parameter sekaligus beberapa parameter per daftar? . Saya hanya akan menyalinnya di sini, tetapi kreditnya ditujukan kepada Knut Arne Vedaa, Kevin Wright, dan tanpa persiapan.

Pertama: Anda dapat memiliki beberapa argumen var:

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

... yang tidak mungkin dalam daftar argumen tunggal.

Kedua, membantu inferensi jenis:

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

Dan terakhir, ini adalah satu-satunya cara Anda dapat memiliki argumen implisit dan non implisit, seperti implicit adalah pengubah untuk daftar argumen lengkap:

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

81
2017-07-23 23:21



Ada perbedaan lain yang tidak tercakup oleh 0 __ yang sangat baik menjawab: parameter default. Parameter dari satu daftar parameter dapat digunakan saat menghitung default dalam daftar parameter lain, tetapi tidak dalam yang sama.

Sebagai contoh:

def f(x: Int, y: Int = x * 2) = x + y // not valid
def g(x: Int)(y: Int = x * 2) = x + y // valid

39
2017-07-26 02:57



Itulah intinya, adalah bahwa bentuk-bentuk kari dan tidak teruraikan itu setara! Seperti yang telah ditunjukkan oleh orang lain, satu atau bentuk lainnya dapat secara sintaksis lebih nyaman untuk bekerja dengan tergantung pada situasi, dan itulah satu-satunya alasan untuk lebih memilih satu dari yang lain.

Penting untuk memahami bahwa bahkan jika Scala tidak memiliki sintaks khusus untuk menyatakan fungsi curried, Anda masih bisa membuatnya; ini hanya ketidakmampuan matematika setelah Anda memiliki kemampuan untuk membuat fungsi yang mengembalikan fungsi.

Untuk mendemonstrasikan ini, bayangkan bahwa def foo(a)(b)(c) = {...} sintaks tidak ada. Maka Anda masih bisa mencapai hal yang persis sama seperti: def foo(a) = (b) => (c) => {...}.

Seperti banyak fitur di Scala, ini hanya kenyamanan sintaksis untuk melakukan sesuatu yang mungkin, tetapi dengan sedikit lebih banyak verbositas.


18
2017-07-23 23:18



Kedua bentuk itu bersifat isomorfik. Perbedaan utamanya adalah fungsi curried lebih mudah diterapkan secara parsial, sementara fungsi non-curried memiliki sintaks yang sedikit lebih baik, setidaknya di Scala.


4
2017-07-23 20:55