11

Enumlar hakkında saçma sapan deliller oluştururken, kazan levhalarından kurtulmanın herhangi bir hilesi var mı?

data WineStock : Fruit -> Type where 
    CanonicalWine : WineStock Grape 
    CiderIsWineToo : WineStock Apple 

Banana, Orange, Lemon ve diğerleri için tutmaz ki, bu reklam

data Fruit = Apple | Banana | Grape | Orange | Lemon | {- many others -} 

ve bu türler üzerinde bir yüklemi var diyelim. Bu WineStock, Fruit; (Biz bu tür bir değeri/kanıt oluşturmak çünkü: CanonicalWine) WineStock Grape doğru olduğu WineStock Apple yanı sıra, ancak bu tür herhangi bir değer/deliller yaşadığı değildir çünkü WineStock Banana, yanlış olup. Sonra


, nasıl etkin bir şekilde Not (WineStock Banana), Not (WineStock Lemon), vs kullanımı hakkında gidebilir? Grape ve Apple yanında her Fruit yapıcısı için ben impossible s, tam yardım ama bir yerde, WineStock üzerinde bir vaka bölünmüş kadar kodlamak için olamaz gibi görünüyor:

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 

Not olun:

  • kodu yinelenen,
  • Yükleme tanımı büyüdüğünde, daha fazla kurucu kazandığında LoC patlayacaktır. Sadece Fruit tanımında birçok tatlı alternatif olduğunu varsayarak, Not (Sweet Lemon) kanıtı hayal edin.

Yani, bu şekilde oldukça, neredeyse pratik tatmin edici görünmemektedir.

Daha şık yaklaşımlar var mı?

+3

Eski Haskell deyimlerinin çoğu, bağımlı yazılan sistemlerde değişmez. “Yasadışı devletleri temsil edilemez hale getirin” türünde de tutuyor: Ben bu imkansız türleri bile yapabilmeniz gerektiğini düşünmüyorum. Muhtemelen bu örneği şarabın yapabildiği bir tür meyveye (kabaca benzer bir şekilde) yapılandırabilirdim WineFruit = Üzüm | Apple' ve diğer meyveler' verileri Fruit = WineFruit WineFruit | Muz | Portakal | Limon ' –

+4

@BenjaminHodgson, bu yaklaşım' PieFruit ',' SaladFruit ',' WeaponFruit ', vb eklemek istediğinizde parçalara ayrılmaya başlar. – dfeuer

+2

Eğer idris içinde olduğunuz göz önüne alındığında, neden' WineStock 'için bir veri türü tanımlıyorsunuz ? 'IsWineStock' değerini bir değer seviyesi işlevi olarak tanımlayamıyor ve uygun olduğu durumlarda ispatlarda kullanamıyor musunuz? – sclv

cevap

4

@slcv haklıdır: bir meyveyi karşılayıp karşılamadığını hesaplayan bir işlevi kullanarak çeşitli indüktif yüklemler yapmak yerine bu yükten kurtulmanızı sağlayacaktır.

data Is : (p : a -> Bool) -> a -> Type where 
    Indeed : p x = True -> Is p x 

isnt : {auto eqF : p a = False} -> Is p a -> b 
isnt {eqF} (Indeed eqT) = case trans (sym eqF) eqT of 
          Refl impossible 

Is p x mülkiyet p eleman x (İdris bağlamda o açılmak kalmaması ben bir endüktif tip ziyade bir tür takma kullanılan tutan olmasını sağlar: Burada

asgari kurulumdur bir delikten, bu şekilde okumak daha kolay).

isnt prf typechecker (Refl ile veya bağlamda bir varsayım) otomatik olarak p a = False bir kanıt oluşturmak mümkün olduğu zaman sahte kanıt prf reddetmektedir.

bu olduktan sonra, sadece pozitif vaka numaralandırma ve Uygun karar fonksiyonu ile Is çağıran tipi takma ad olarak orijinal yüklemler tanımlayabilirsiniz

wineFruit : Fruit -> Bool 
wineFruit Grape = True 
wineFruit Apple = True 
wineFruit _  = False 

weaponFruit : Fruit -> Bool 
weaponFruit Apple = True 
weaponFruit Orange = True 
weaponFruit Lemon = True 
weaponFruit _  = False 

herkesi kucaklayan ekleyerek özelliklerini tanımlayan başlayabilirsiniz:

:
WineStock : Fruit -> Type 
WineStock = Is wineFruit 

Ve yeterince emin, isnt sen imkansız davaları görevden verir

dismiss : WineStock Orange -> Void 
dismiss = isnt 
+0

Vay, harika, teşekkürler! – ulidtko