2012-06-28 25 views
9

Vì vậy, cuối cùng tôi đã tìm thấy một tác vụ mà tôi có thể sử dụng phần mở rộng DataKinds mới (sử dụng ghc 7.4.1). Đây là Vec Tôi đang sử dụng:Tên liên kết trong chữ ký loại sử dụng DataKind

data Nat = Z | S Nat deriving (Eq, Show) 

data Vec :: Nat -> * -> * where 
    Nil :: Vec Z a 
    Cons :: a -> Vec n a -> Vec (S n) a 

Bây giờ, để thuận tiện tôi muốn thực hiện fromList. Về cơ bản không có vấn đề với đệ quy đơn giản/fold - nhưng tôi không thể tìm ra cách để cho nó đúng loại. Để tham khảo, đây là phiên bản Agda:

fromList : ∀ {a} {A : Set a} → (xs : List A) → Vec A (List.length xs) 

My Haskell cách tiếp cận, sử dụng cú pháp tôi thấy here:

fromList :: (ls :: [a]) -> Vec (length ls) a 
fromList [] = Nil 
fromList (x:xs) = Cons x (fromList xs) 

này mang lại cho tôi một parse error on input 'a'. Cú pháp tôi tìm thấy có chính xác không, hoặc họ đã thay đổi nó chưa? Tôi cũng đã thêm một số tiện ích mở rộng khác có trong mã trong liên kết, điều này không giúp được gì (hiện tại tôi có GADTs, DataKinds, KindSignatures, TypeOperators, TypeFamilies, UndecidableInstances).

nghi ngờ khác của tôi là tôi chỉ không thể ràng buộc kiểu đa hình, nhưng thử nghiệm của tôi cho điều này:

bla :: (n :: Nat) -> a -> Vec (S n) a 
bla = undefined 

thất bại, quá, với Kind mis-match Expected kind 'ArgKind', but 'n' has kind 'Nat' (thật sự không biết điều đó có nghĩa).

Có ai có thể giúp tôi với phiên bản làm việc của fromList và cũng làm rõ các vấn đề khác không? Thật không may, DataKinds không được tài liệu rất tốt và dường như giả định rằng tất cả mọi người sử dụng nó có kiến ​​thức lý thuyết loại sâu sắc.

Trả lời

9

Haskell, không giống như Agda, không có loại phụ thuộc, vì vậy không có cách nào để thực hiện chính xác những gì bạn muốn. Các kiểu không thể được tham số hóa theo giá trị, vì Haskell thực thi một sự phân biệt pha giữa thời gian chạy và thời gian biên dịch. Cách DataKinds hoạt động khái niệm thực sự thực sự đơn giản: các kiểu dữ liệu được quảng cáo cho các loại (loại kiểu) và trình tạo dữ liệu được quảng bá cho các loại.

fromList :: (ls :: [a]) -> Vec (length ls) a 

có một vài vấn đề: (ls :: [a]) không thực sự có ý nghĩa (ít nhất là khi bạn chỉ giả mạo các loại phụ thuộc với chương trình khuyến mãi), và length là một loại biến thay vì một loại chức năng. Những gì bạn muốn nói là

fromList :: [a] -> Vec ??? a 

trong đó ??? là độ dài của danh sách. Vấn đề là bạn không có cách nào nhận được độ dài của danh sách tại thời gian biên dịch ... vì vậy chúng tôi có thể thử

fromList :: [a] -> Vec len a 

nhưng điều này là sai, vì nó nói rằng fromList có thể trả về một danh sách của bất kỳ chiều dài. Thay vào đó, điều chúng tôi muốn nói là

fromList :: exists len. [a] -> Vec len a 

nhưng Haskell không hỗ trợ điều này. Thay vào đó

data VecAnyLength a where 
    VecAnyLength :: Vec len a -> VecAnyLength a 

cons a (VecAnyLength v) = VecAnyLength (Cons a v) 

fromList :: [a] -> VecAnyLength a 
fromList []  = VecAnyLength Nil 
fromList (x:xs) = cons x (fromList xs) 

bạn thực sự có thể sử dụng một VecAnyLength bởi mô hình kết hợp, và do đó nhận được một giá trị (địa phương) psuedo-lệ thuộc gõ.

tương tự,

bla :: (n :: Nat) -> a -> Vec (S n) a 

không làm việc vì chức năng Haskell chỉ có thể đưa đối số của loại *. Thay vào đó bạn có thể thử

data HNat :: Nat -> * where 
    Zero :: HNat Z 
    Succ :: HNat n -> HNat (S n) 

bla :: HNat n -> a -> Ven (S n) a 

mà thậm chí còn định nghĩa

bla Zero a  = Cons a Nil 
bla (Succ n) a = Cons a (bla n a) 
+1

Wow, cảm ơn rất nhiều. Điều này làm cho tôi bắt đầu thực sự hiểu 'DataKinds' - họ đánh lừa tôi một chút, có vẻ như vậy. Thật vậy, lúc đầu, tôi nghĩ rằng tôi cần phiên bản được định lượng hiện tại, nhưng kiểu phụ thuộc trông giống như những gì tôi thực sự muốn loại thể hiện. Tuy nhiên, cú pháp ràng buộc với '(a :: X) -> Y' đến từ đâu? Tôi đã thấy điều đó ở một số nơi. – phg

+0

Ví dụ, nó được sử dụng [ở đây] (http://haskell.1045720.n5.nabble.com/Data-Kinds-and-superfluous-in-my-opinion-constraints-contexts-td5689436.html), và tôi cũng nghĩ [ở đây] (http://www.typesandotherdistractions.com/2012/02/fun-with-xpolykinds-polykinded-folds.html). – phg

+0

Tôi nghĩ rằng hầu hết những gì bạn có là mã ở cấp độ hạn '\ (a :: X) -> y' và/hoặc các công cụ liên quan đến' PolyKinds'. Ví dụ: 'dữ liệu Hộp a = Hộp' và' bla :: Hộp (n :: Nat) -> a -> Vec n a' –

3

Bạn có thể sử dụng một số phép thuật typeclass đây (xem HList để biết thêm):

{-# LANGUAGE GADTs, KindSignatures, DataKinds, FlexibleInstances 
    , NoMonomorphismRestriction, FlexibleContexts #-} 

data Nat = Z | S Nat deriving (Eq, Show) 

data Vec :: Nat -> * -> * where 
    Nil :: Vec Z a 
    Cons :: a -> Vec n a -> Vec (S n) a 

instance Show (Vec Z a) where 
    show Nil = "." 

instance (Show a, Show (Vec m a)) => Show (Vec (S m) a) where 
    show (Cons x xs) = show x ++ " " ++ show xs 

class FromList m where 
    fromList :: [a] -> Vec m a 

instance FromList Z where 
    fromList [] = Nil 

instance FromList n => FromList (S n) where 
    fromList (x:xs) = Cons x $ fromList xs 

t5 = fromList [1, 2, 3, 4, 5] 

nhưng điều này không thực sự giải quyết vấn đề :

> :t t5 
t5 :: (Num a, FromList m) => Vec m a 

Danh sách được hình thành trong thời gian chạy, thời gian của họ không được biết đến tại thời gian biên dịch, vì vậy trình biên dịch không thể suy ra kiểu cho t5, nó phải được xác định một cách rõ ràng:

*Main> t5 

<interactive>:99:1: 
    Ambiguous type variable `m0' in the constraint: 
     (FromList m0) arising from a use of `t5' 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: t5 
    In an equation for `it': it = t5 
*Main> t5 :: Vec 'Z Int 
*** Exception: /tmp/d.hs:20:3-19: Non-exhaustive patterns in function fromList 

*Main> t5 :: Vec ('S ('S ('S 'Z))) Int 
1 2 3 *** Exception: /tmp/d.hs:20:3-19: Non-exhaustive patterns in function fromList 

*Main> t5 :: Vec ('S ('S ('S ('S ('S 'Z))))) Int 
1 2 3 4 5 . 
*Main> t5 :: Vec ('S ('S ('S ('S ('S ('S ('S 'Z))))))) Int 
1 2 3 4 5 *** Exception: /tmp/d.hs:23:3-40: Non-exhaustive patterns in function fromList 

Ngôn ngữ với các loại phụ thuộc có bản đồ từ về các loại, loại có thể được hình thành động trong thời gian chạy quá, do đó, vấn đề này không tồn tại.

+2

Các loại có thể được 'hình thành động tại thời gian chạy' trong Haskell, ví dụ: 'runtimetype :: Hiển thị a => a -> Số nguyên -> Chuỗi; runtimetype x n = case n của {0 -> hiển thị x; _ -> runtimetype (Chỉ cần x) (n- (1 :: Số nguyên)); main = tương tác $ (++ "\ n"). runtimetype(). đọc 'Điều này sẽ in một điều của một loại khác nhau cho mỗi số nguyên hợp lệ nó đọc từ stdin. Đây là ví dụ thực hiện nó http://ideone.com/dAK0K – applicative

+0

Dưới đây là một ví dụ tốt hơn, nó đưa ra một chuỗi chiều dài n nó in một n-tuple với các ký tự http://ideone.com/mcQfl Nó là một chút như 'fromList' mà op muốn. – applicative

+1

@ ứng dụng này là thú vị. Tuy nhiên, các kiểu khác nhau xuất hiện trong đối số ở đây, nhưng 'fromList' có cụm từ -> type (well, một kiểu dữ liệu' Nat') phụ thuộc vào kết quả. Tôi thấy rằng 'HList' bao gồm một định nghĩa cho các bản đồ từ các bộ sưu tập không đồng nhất đến đồng nhất, nhưng không phải định nghĩa nghịch đảo. – JJJ

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