Mengapa Scala membutuhkan fungsi untuk memiliki tipe pengembalian eksplisit?

11

Saya baru-baru ini mulai belajar program di Scala, dan sejauh ini menyenangkan. Saya sangat suka kemampuan untuk mendeklarasikan fungsi di dalam fungsi lain yang sepertinya merupakan hal yang intuitif untuk dilakukan.

Salah satu kesal yang saya miliki tentang Scala adalah fakta bahwa Scala membutuhkan tipe pengembalian eksplisit dalam fungsinya . Dan saya merasa seperti ini menghalangi ekspresi bahasa. Juga hanya sulit untuk memprogram dengan persyaratan itu. Mungkin itu karena saya berasal dari zona kenyamanan Javascript dan Ruby. Tetapi untuk bahasa seperti Scala yang akan memiliki banyak fungsi yang terhubung dalam suatu aplikasi, saya tidak dapat membayangkan bagaimana saya melakukan brainstorming di kepala saya persis apa jenis fungsi tertentu yang saya tulis harus kembali dengan rekursi setelah rekursi.

Persyaratan deklarasi tipe pengembalian eksplisit tentang fungsi ini, jangan ganggu saya untuk bahasa seperti Java dan C ++. Rekursi di Jawa dan C ++, ketika itu terjadi, sering ditangani dengan 2 hingga 3 fungsi maks. Tidak pernah beberapa fungsi dirantai bersama seperti Scala.

Jadi saya kira saya bertanya-tanya apakah ada alasan bagus mengapa Scala harus memiliki persyaratan fungsi yang memiliki tipe pengembalian eksplisit?

pengumpulan sampah
sumber
5
Tidak - dan saya gagal melihat mengapa itu akan menjadi masalah jika itu terjadi.
Keith Thompson
1
Saya pikir itu terjadi. Apakah ada kasus di Scala di mana tipe pengembalian untuk fungsi sebenarnya ambigu?
pengumpulan sampah

Jawaban:

15

Scala tidak memerlukan jenis pengembalian eksplisit pada semua fungsi, hanya yang rekursif. Alasan untuk itu adalah bahwa algoritma inferensi tipe Scala adalah (sesuatu yang dekat dengan) pemindaian sederhana dari awal hingga akhir yang tidak mampu melihat lookhead.

Ini berarti bahwa fungsi seperti ini:

def fortuneCookieJoke(message: String) = message + " in bed."

tidak memerlukan tipe kembali, karena kompilator Scala dapat melihat dengan jelas, tanpa menggunakan variabel logika atau melihat apa pun selain parameter metode, bahwa jenis kembali harus String.

Di sisi lain, fungsi seperti ini:

def mapInts(f: (Int) => Int, l: List[Int]) = l match {
  case Nil => Nil
  case x :: xs => f(x) :: mapInts(f, xs)
}

akan menyebabkan kesalahan waktu kompilasi, karena kompilator Scala tidak dapat melihat, tanpa menggunakan variabel lookahead atau logika, dengan tepat apa jenisnya mapInts. Yang paling bisa dikatakan, jika itu cukup pintar, adalah bahwa tipe kembalinya adalah supertipe List[Nothing], karena Niltipe itu. Itu tidak memberikan informasi yang cukup dekat untuk menentukan secara akurat jenis pengembalian mapInts.

Harap perhatikan bahwa ini khusus untuk Scala, dan bahwa ada bahasa lain yang diketik secara statis (sebagian besar keluarga Miranda / Haskell / Clean, sebagian besar keluarga ML, dan beberapa lainnya yang tersebar) yang menggunakan algoritma inferensi jenis yang jauh lebih komprehensif dan mampu. dari yang digunakan Scala. Perlu diketahui juga bahwa ini bukan sepenuhnya kesalahan Scala; subtipe nominal dan inferensi tipe seluruh modul pada dasarnya bertentangan satu sama lain, dan para perancang Scala memilih untuk memilih yang pertama daripada yang kedua demi Java, sedangkan bahasa fungsional yang "murni" yang diketik secara statis sebagian besar dirancang dengan pilihan yang berlawanan dalam pikiran.

Api Ptharien
sumber
4
Sebenarnya, masalahnya tidak terlalu banyak mencari tahu jenis algoritma menyimpulkan yang lebih komprehensif. Ini mencari tahu jenis algoritma menyimpulkan yang lebih komprehensif, sambil menjaga kualitas tinggi pesan kesalahan dalam kompiler Scala saat ini.
Jörg W Mittag
1
Bukankah pengembalian yang benar untuk case Nilbenar - benar kosong List[Int]()? Dalam hal ini kompiler yang cukup pintar bisa mengetahuinya. Tapi itu semua bermain sebagai Pengacara Setan, kurasa.
KChaloux