11

Hãy nói rằng tôi cóBất kỳ thủ thuật nào để loại bỏ bản mẫu khi xây dựng bằng chứng về vị từ vô lý trên enums?

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

và một vị vào loại đó,

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

mà không giữ cho Banana, Orange, Lemon và những người khác.

can be said rằng điều này xác định WineStock làm vị từ trên Fruit; WineStock Grapeđúng (vì chúng ta có thể xây dựng một giá trị/bằng chứng về loại rằng: CanonicalWine) cũng như WineStock Apple, nhưng WineStock Bananasai, vì loại đó là không nơi sinh sống của bất kỳ giá trị/chứng minh.


Sau đó, làm thế nào tôi có thể đi về việc sử dụng một cách hiệu quả Not (WineStock Banana), Not (WineStock Lemon), vv? Dường như đối với từng Fruit constructor ngoài GrapeApple, tôi không thể giúp đỡ, nhưng phải mã lên một sự chia rẽ trường hợp trên WineStock, ở đâu đó, đầy 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 

Lưu ý rằng:

  • mã lặp lại,
  • LoC sẽ phát nổ khi định nghĩa vị ngữ phát triển, thu được nhiều hàm tạo hơn. Chỉ cần tưởng tượng bằng chứng Not (Sweet Lemon), giả sử có nhiều lựa chọn thay thế ngọt theo định nghĩa Fruit.

Vì vậy, cách này dường như không thỏa mãn, gần như không thực tế.

Có cách tiếp cận trang nhã hơn không?

+3

Nhiều thành ngữ Haskell cũ không thay đổi trong các hệ thống được đánh máy phụ thuộc. "Làm cho các quốc gia bất hợp pháp không thể đại diện được" giữ ở cấp độ loại quá: Tôi không nghĩ rằng bạn thậm chí có thể xây dựng những loại không thể đó. Tôi có lẽ sẽ cấu trúc ví dụ này như (một cái gì đó gần giống như) một loại trái cây có thể làm cho rượu vang 'dữ liệu WineFruit = nho | Apple 'và các loại trái cây khác' dữ liệu Trái cây = Rượu vangTháp Rượu vang | Chuối | Orange | Lemon' –

+4

@BenjaminHodgson, cách tiếp cận đó bắt đầu sụp đổ khi bạn muốn thêm 'PieFruit',' SaladFruit', 'WeaponFruit', v.v. – dfeuer

+2

Cho rằng bạn đang ở trong idris, tại sao bạn định nghĩa một kiểu dữ liệu cho' WineStock' ? Bạn có thể không chỉ định nghĩa 'isWineStock' như một hàm mức giá trị và sử dụng nó trong các chứng minh khi thích hợp? – sclv

Trả lời

4

@slcv là đúng: sử dụng hàm tính toán liệu quả có đáp ứng thuộc tính hay không thay vì xây dựng các biến vị ngữ cảm ứng khác nhau sẽ cho phép bạn loại bỏ chi phí này.

Đây là thiết lập tối thiểu:

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 bảo rằng tài sản p giữ của phần tử x (Tôi đã sử dụng một loại quy nạp chứ không phải là một loại bí danh để Idris không mở ra nó trong bối cảnh của một lỗ, nó dễ dàng hơn để đọc theo cách này).

isnt prf bác bỏ bằng chứng giả mạo prf bất cứ khi nào typechecker có khả năng tạo ra một bằng chứng cho thấy p a = False tự động (thông qua Refl hoặc một giả định trong bối cảnh).

Một khi bạn có này, bạn có thể bắt đầu xác định tài sản của bạn bằng cách chỉ liệt kê các trường hợp dương tính và thêm một catchall

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 

Bạn có thể xác định vị ban đầu của bạn như loại bí danh gọi Is với chức năng ra quyết định phù hợp:

WineStock : Fruit -> Type 
WineStock = Is wineFruit 

Và, chắc chắn đủ, isnt cho phép bạn bỏ qua những trường hợp bất khả thi:

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

Wow, tuyệt vời, cảm ơn! – ulidtko

Các vấn đề liên quan