2015-04-23 15 views
9

Tôi đang cố xác định loại cho danh sách độ dài cố định trong Haskell. Khi tôi sử dụng cách tiêu chuẩn để mã hóa các số tự nhiên thành các loại đơn nhất, mọi thứ đều hoạt động tốt. Tuy nhiên, khi tôi cố gắng xây dựng mọi thứ trên các loại chữ của GHC, tôi gặp phải rất nhiều vấn đề.Danh sách độ dài và loại chữ cố định

shot đầu tiên của tôi tại các loại danh sách mong muốn là

data List (n :: Nat) a where 
    Nil :: List 0 a 
    (:>) :: a -> List n a -> List (n+1) a 

mà tiếc là không cho phép viết một hàm zip với loại

zip :: List n a -> List n b -> List n (a,b) 

tôi có thể giải quyết vấn đề này bằng cách trừ đi 1 từ loại biến số n trong loại (:>):

data List (n :: Nat) a where 
    Nil :: List 0 a 
    (:>) :: a -> List (n-1) a -> List n a -- subtracted 1 from both n's 

Tiếp theo, tôi đã cố gắng để xác định một chức năng phụ thêm:

append :: List n1 a -> List n2 a -> List (n1 + n2) a 
append Nil  ys = ys 
append (x :> xs) ys = x :> (append xs ys) 

Thật không may, GHC nói với tôi

Couldn't match type ‘(n1 + n2) - 1’ with ‘(n1 - 1) + n2’ 

Thêm chế ((n1 + n2) - 1) ~ ((n1 - 1) + n2) để chữ ký không giải quyết được vấn đề kể từ GHC phàn nàn

Could not deduce ((((n1 - 1) - 1) + n2) ~ (((n1 + n2) - 1) - 1)) 
from the context (((n1 + n2) - 1) ~ ((n1 - 1) + n2)) 

Bây giờ, tôi rõ ràng bị bắt trong một số loại vòng lặp vô hạn.

Vì vậy, tôi muốn biết nếu nó có thể xác định một loại cho các danh sách có độ dài cố định sử dụng literals loại ở tất cả. Có lẽ tôi thậm chí có thể giám sát một thư viện cho chính xác mục đích này? Về cơ bản, yêu cầu duy nhất là tôi muốn viết một cái gì đó như List 3 a thay vì .

+0

Bạn có thể tìm thấy một số cuộc thảo luận về các vấn đề liên quan đến gõ cấp độ dài vector trong giấy Hasochism: https://personal.cis.strath.ac.uk/conor.mcbride/pub/hasochism. pdf – chi

+1

"Hasochism" âm thanh thực sự hấp dẫn. Tuy nhiên, tôi sẽ thử cho bài báo. Cảm ơn bạn. –

+0

Nó có thể dễ dàng hơn để làm cho một wrapper newtype xung quanh một danh sách bình thường với một 'Nat' đính kèm, tương tự như cách' Linear.V' hiện nó. Bạn có thể định nghĩa một số nguyên thủy trong một mô đun và ẩn hàm tạo để làm cho mọi thứ an toàn. – cchalmers

Trả lời

19

Đây không thực sự là câu trả lời.

Sử dụng https://hackage.haskell.org/package/ghc-typelits-natnormalise-0.2, đây

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE TypeOperators #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE KindSignatures #-} 
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-} 

import GHC.TypeLits 

data List (n :: Nat) a where 
    Nil :: List 0 a 
    (:>) :: a -> List n a -> List (n+1) a 

append :: List n1 a -> List n2 a -> List (n1 + n2) a 
append Nil  ys = ys 
append (x :> xs) ys = x :> (append xs ys) 

... biên dịch, vì vậy rõ ràng là nó đúng.

???

+2

Tìm thấy tuyệt vời. –

+0

Tôi không biết về plugin cho trình kiểm tra loại ở tất cả, nhưng hoạt động thực sự độc đáo. Cảm ơn bạn. –

6

literals số Loại mực chưa có một cấu trúc mà chúng tôi có thể làm cảm ứng, và được xây dựng trong chế giải chỉ có thể tìm ra các trường hợp đơn giản nhất. Hiện tại, tốt hơn là nên gắn bó với Peano naturals.

Tuy nhiên, chúng ta vẫn có thể sử dụng các chữ như đường cú pháp.

{-# LANGUAGE 
    UndecidableInstances, 
    DataKinds, TypeOperators, TypeFamilies #-} 

import qualified GHC.TypeLits as Lit 

data Nat = Z | S Nat 

type family Lit n where 
    Lit 0 = Z 
    Lit n = S (Lit (n Lit.- 1)) 

Bây giờ bạn có thể viết List (Lit 3) a thay vì .

+0

Tôi cũng có một ý tưởng tương tự, nhưng sử dụng 'UndecidableInstances' luôn làm tôi sợ một chút. Sử dụng một từ đồng nghĩa khác, tôi thậm chí có thể đến 'List 3 a' rồi. –

+0

Ở đây, kiểu gia đình rõ ràng chấm dứt, do đó, không có vấn đề với 'UndecidableInstances'. Ngay cả trong trường hợp chung, tôi không thấy nó thực sự đáng sợ. Nếu chúng tôi vô tình viết mã loại cấp độ khác nhau, chúng tôi hầu như luôn nhận được lỗi giới hạn độ sâu ngữ cảnh. Rất hiếm khi chúng ta thực sự có được vòng lặp GHC, và chúng ta có thể dễ dàng khắc phục vấn đề đó với một Ctr-c. –

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