มันเป็นความเข้าใจผิดที่พบบ่อยซึ่งเราสามารถแปลlet
-Expresions ไปยังแอปพลิเคชัน ความแตกต่างระหว่างlet x : t := b in v
และ(fun x : t => v) b
คือในlet
-expression ในระหว่างการตรวจสอบชนิดของv
เรารู้ว่าx
มีค่าเท่ากับb
แต่ในแอปพลิเคชันที่เราทำไม่ได้ (subexpression fun x : t => v
ต้องทำให้รู้สึกด้วยตัวเอง)
นี่คือตัวอย่าง:
(* 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).
คำแนะนำของคุณในการทำให้แอปพลิเคชัน(fun x : t => v) b
เป็นกรณีพิเศษไม่ได้ผลจริงๆ ให้เราคิดอย่างรอบคอบมากขึ้น
ตัวอย่างเช่นคุณจะจัดการกับเรื่องนี้อย่างไรดำเนินการตามตัวอย่างด้านบน
Definition a := (fun (n : nat) => cons n 42 nil).
Check a 0.
สันนิษฐานว่าสิ่งนี้จะไม่ทำงานเพราะa
ไม่สามารถพิมพ์ได้ แต่ถ้าเราเปิดเผยคำจำกัดความเราจะได้รับนิพจน์ที่พิมพ์ได้ดี คุณคิดว่าผู้ใช้จะรักเราหรือเกลียดเราในการตัดสินใจออกแบบของเราหรือไม่?
คุณต้องคิดให้ถี่ถ้วนว่าการมี "กรณีพิเศษ" หมายความว่าอย่างไร หากฉันมีแอปพลิเคชันe₁ e₂
ฉันควรทำให้เป็นมาตรฐานe₁
ก่อนที่จะตัดสินใจว่าเป็นแอปพลิเคชันหรือไม่λ-abstraction? ถ้าใช่นี่หมายความว่าฉันจะทำให้นิพจน์ที่พิมพ์ผิดกลับคืนมาและสิ่งเหล่านั้นอาจวนซ้ำ หากไม่มีการใช้งานข้อเสนอของคุณน่าสงสัย
คุณจะทำลายทฤษฏีพื้นฐานที่บอกว่านิพจน์ย่อยที่พิมพ์ได้ดีนั้นถูกพิมพ์ออกมาอย่างดี มันมีเหตุผลพอ ๆ กับการแนะนำให้รู้จักnull
กับจาวา
let
นิพจน์ แต่มี) เหตุผลในการหลีกเลี่ยงlet
การแสดงออกและยังสะดวกและข) การเพิ่มแฮ็กในภาษาหลักของคุณไม่ใช่ความคิดที่ดี