È let
un'idea sbagliata comune che possiamo tradurre -espressioni in applicazioni. La differenza tra let x : t := b in v
e (fun x : t => v) b
è che let
nell'espressione, durante la verifica del tipo di v
sappiamo che x
è uguale a b
, ma nell'applicazione non lo facciamo (la sottoespressione fun x : t => v
deve avere senso da sola).
Ecco un esempio:
(* 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).
Il tuo suggerimento di rendere l'applicazione (fun x : t => v) b
un caso speciale non funziona davvero. Pensiamoci più attentamente.
Ad esempio, come gestiresti questo, continuando l'esempio sopra?
Definition a := (fun (n : nat) => cons n 42 nil).
Check a 0.
Presumibilmente questo non funzionerà perché a
non può essere digitato, ma se spieghiamo la sua definizione, otteniamo un'espressione ben digitata. Pensi che gli utenti ci ameranno o ci odieranno per la nostra decisione di progettazione?
Devi pensare attentamente cosa significa avere il "caso speciale". Se ho un'applicazione e₁ e₂
, dovrei normalizzarmi e₁
prima di decidere se si tratta di una -abstraction? In caso affermativo, ciò significa che normalizzerò espressioni mal digitate e che potrebbero scorrere. In caso contrario, l'usabilità della tua proposta sembra discutibile.λ
Si romperebbe anche il teorema fondamentale secondo cui ogni sottoespressione di un'espressione ben tipizzata è ben tipizzata. È sensato quanto introdurlo null
in Java.
let
espressioni, ma non c'è a) alcun motivo per evitare lelet
espressioni e sono anche convenienti, e b) aggiungere hack al tuo linguaggio principale non è una grande idea.