2014-04-29 20 views
8

Tôi có đoạn code sau, và tôi sẽ như thế này để thất bại kiểm tra kiểu:Làm cách nào để sử dụng các hạn chế bị hạn chế với GADT?

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE GADTs #-} 
{-# LANGUAGE RankNTypes #-} 

import Control.Lens 

data GADT e a where 
    One :: Greet e => String -> GADT e String 
    Two :: Increment e => Int -> GADT e Int 

class Greet a where 
    _Greet :: Prism' a String 

class Increment a where 
    _Increment :: Prism' a Int 

instance Greet (Either String Int) where 
    _Greet = _Left 

instance Increment (Either String Int) where 
    _Increment = _Right 

run :: GADT e a -> Either String Int 
run = go 
    where 
    go (One x) = review _Greet x 
    go (Two x) = review _Greet "Hello" 

Ý tưởng là mỗi mục trong GADT có lỗi liên quan, mà tôi đang mô hình hóa với một Prism vào một số cấu trúc lớn hơn. Khi tôi "giải thích" GADT này, tôi cung cấp một loại cụ thể cho e có các phiên bản cho tất cả các số này là Prism s. Tuy nhiên, đối với từng trường hợp riêng lẻ, tôi không muốn có thể sử dụng các cá thể không được khai báo trong ngữ cảnh liên quan của hàm tạo.

Mã trên phải là một lỗi, vì khi tôi khớp mẫu trên Two Tôi nên tìm hiểu rằng tôi chỉ có thể sử dụng Increment e, nhưng tôi đang sử dụng Greet. Tôi có thể thấy lý do tại sao thao tác này hoạt động - Either String Int có một phiên bản cho Greet, vì vậy mọi thứ đều kiểm tra.

Tôi không chắc cách tốt nhất để khắc phục điều này là gì. Có lẽ tôi có thể sử dụng entailment từ Data.Constraint hoặc có thể có một mẹo với các loại xếp hạng cao hơn.

Bất kỳ ý tưởng nào?

Trả lời

7

Vấn đề là bạn đang sửa chữa loại kết quả cuối cùng, vì vậy bản sao tồn tại và trình kiểm tra loại có thể tìm thấy nó.

Hãy thử một cái gì đó như:

run :: GADT e a -> e 

Bây giờ loại kết quả không thể chọn ví dụ cho review và parametricity thực thi bất biến của bạn.

+1

Để mở rộng điều này, Ed là đúng - phần quan trọng là bạn cung cấp 'e' tại điểm * gọi * chạy, thay vì định nghĩa' run'. – ocharles

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