Diciamo che hoEventuali trucchi per sbarazzarsi di boilerplate quando si costruiscono prove di assurdo predicato sulle enumerazioni?
data Fruit = Apple | Banana | Grape | Orange | Lemon | {- many others -}
e un predicato su quel tipo,
data WineStock : Fruit -> Type where
CanonicalWine : WineStock Grape
CiderIsWineToo : WineStock Apple
che non detiene per Banana
, Orange
, Lemon
e altri.
E 'can be said che questo definisce WineStock
come un predicato su Fruit
; WineStock Grape
è vero (dal momento che siamo in grado di costruire un valore/prova di questo tipo: CanonicalWine
), così come WineStock Apple
, ma WineStock Banana
è falso, dal momento che il tipo non è abitata da eventuali valori/prove.
Poi, come posso andare su come utilizzare in modo efficace Not (WineStock Banana)
, Not (WineStock Lemon)
, ecc? Sembra che per ogni costruttore Fruit
oltre Grape
e Apple
, non posso fare a meno di codificare un caso suddiviso su WineStock
, da qualche parte, pieno di impossible
s:
instance Uninhabited (WineStock Banana) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
instance Uninhabited (WineStock Lemon) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
instance Uninhabited (WineStock Orange) where
uninhabited CanonicalWine impossible
uninhabited CiderIsWineToo impossible
Nota che:
- il codice è ripetitivo,
- LoC esploderà quando la definizione del predicato aumenta, acquisendo più costruttori. Immagina solo la prova
Not (Sweet Lemon)
, supponendo che ci siano molte alternative dolci nella definizioneFruit
.
Quindi, in questo modo non del tutto soddisfacente sembra, quasi impraticabile .
Ci sono approcci più eleganti?
Molti dei vecchi idiomi di Haskell non cambiano nei sistemi tipizzati in modo dipendente. "Rendere gli stati illegali non rappresentabili" vale anche a livello di tipo: non penso che dovresti essere in grado di costruire quei tipi impossibili. Probabilmente strutturerei questo esempio come (qualcosa di simile a) un tipo di frutta che può rendere il vino 'data WineFruit = Grape | Apple' e altri frutti 'dati Fruit = WineFruit WineFruit | Banana | Arancione | Lemon' –
@BenjaminHodgson, questo approccio inizia a crollare quando si desidera aggiungere 'PieFruit',' SaladFruit', 'WeaponFruit', ecc. – dfeuer
Dato che sei in idris, perché stai definendo un tipo di dati per' WineStock' ? Non puoi semplicemente definire 'isWineStock' come una funzione a livello di valore e usarla nelle dimostrazioni dove appropriato? – sclv