Ini adalah kesalahpahaman umum bahwa kita dapat menerjemahkan let
-ekspresi ke aplikasi. Perbedaan antara let x : t := b in v
dan (fun x : t => v) b
adalah bahwa dalam let
-ekspresi, selama pengecekan tipe v
kita tahu bahwa x
sama dengan b
, tetapi dalam aplikasi kita tidak (subekspresi fun x : t => v
harus masuk akal sendiri).
Berikut ini sebuah contoh:
(* Dependent type of vectors. *)
Inductive Vector {A : Type} : nat -> Type :=
| nil : Vector 0
| cons : forall n, A -> Vector n -> Vector (S n).
(* This works. *)
Check (let n := 0 in cons n 42 nil).
(* This fails. *)
Check ((fun (n : nat) => cons n 42 nil) 0).
Saran Anda untuk membuat aplikasi (fun x : t => v) b
kasus khusus tidak benar-benar berfungsi. Mari kita pikirkan lebih hati-hati.
Misalnya, bagaimana Anda akan menangani ini, melanjutkan contoh di atas?
Definition a := (fun (n : nat) => cons n 42 nil).
Check a 0.
Agaknya ini tidak akan berhasil karena a
tidak bisa diketik, tetapi jika kita membuka definisi, kita mendapatkan ekspresi yang diketik dengan baik. Apakah Anda pikir pengguna akan mencintai kami, atau membenci kami karena keputusan desain kami?
e₁ e₂
e₁
λ
Anda juga akan mematahkan teorema dasar yang mengatakan bahwa setiap sub-ekspresi dari ekspresi yang diketik dengan baik diketik dengan baik. Itu masuk akal seperti memperkenalkan null
ke Jawa.
let
ekspresi, tetapi ada a) tidak ada alasan untuk menghindarilet
ekspresi dan mereka juga nyaman, dan b) menambahkan peretasan ke bahasa inti Anda bukan ide yang bagus.