É um equívoco comum que possamos converter let
expressões -ex em aplicativos. A diferença entre let x : t := b in v
e (fun x : t => v) b
é que na let
expressão-, durante a verificação de tipo v
, sabemos que x
é igual a b
, mas na aplicação, não (a subexpressão fun x : t => v
deve fazer sentido por si só).
Aqui está um exemplo:
(* 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).
Sua sugestão para tornar a aplicação (fun x : t => v) b
um caso especial não funciona realmente. Vamos pensar sobre isso com mais cuidado.
Por exemplo, como você lidaria com isso, continuando o exemplo acima?
Definition a := (fun (n : nat) => cons n 42 nil).
Check a 0.
Presumivelmente, isso não funcionará porque a
não pode ser digitado, mas se desdobrarmos sua definição, obteremos uma expressão bem digitada. Você acha que os usuários vão nos amar ou nos odiar por nossa decisão de design?
e₁ e₂
e₁
λ
Você também quebraria o teorema fundamental que diz que toda sub-expressão de uma expressão bem digitada é bem digitada. Isso é tão sensato quanto a introdução null
ao Java.
let
expressões, mas não há motivo para evitarlet
expressões e elas também são convenientes eb) adicionar hacks à sua linguagem principal não é uma boa idéia.