2012-04-17 24 views
26

Khi sử dụng các loại Existential, chúng ta phải sử dụng cú pháp khớp mẫu để trích xuất giá trị ed forall. Chúng tôi không thể sử dụng bộ chọn bản ghi thông thường làm chức năng. GHC báo cáo lỗi và đề nghị sử dụng mô hình khớp với định nghĩa này của yALL:Tại sao tôi không thể sử dụng bộ chọn bản ghi với loại định lượng hiện có?

{-# LANGUAGE ExistentialQuantification #-} 

data ALL = forall a. Show a => ALL { theA :: a } 
-- data ok 

xALL :: ALL -> String 
xALL (ALL a) = show a 
-- pattern matching ok 

-- ABOVE: heaven 
-- BELOW: hell 

yALL :: ALL -> String 
yALL all = show $ theA all 
-- record selector failed 

forall.hs:11:19: 
    Cannot use record selector `theA' as a function due to escaped type variables 
    Probable fix: use pattern-matching syntax instead 
    In the second argument of `($)', namely `theA all' 
    In the expression: show $ theA all 
    In an equation for `yALL': yALL all = show $ theA all 

Một số dữ liệu của tôi mất hơn 5 yếu tố. Thật khó để duy trì mã nếu tôi sử dụng mô hình khớp:

func1 (BigData _ _ _ _ elemx _ _) = func2 elemx 

Có một phương pháp tốt để làm cho mã như vậy duy trì hoặc để quấn nó lên để tôi có thể sử dụng một số loại selectors?

+3

Gợi ý: Loại 'theA' là gì? –

+0

@Louis Wasserman: bạn có nghĩa là sử dụng cú pháp tồn tại trong yALL không? làm sao? – Nybble

+0

Về cơ bản, câu trả lời là nó _doesn't_ có một loại rõ ràng, vì vậy bạn cần khớp mẫu để có được một loại khả thi. –

Trả lời

15

Bạn có thể sử dụng cú pháp kỷ lục trong mô hình kết hợp,

func1 BigData{ someField = elemx } = func2 elemx 

công trình và ít nhiều đánh máy với nhiều loại rất lớn.

+0

Câu trả lời hay! Tôi chỉ tìm thấy nó sau: dữ liệu B {x :: Int, y :: Int}; vui vẻ B {..} = x + y; đó có thể là một thay thế. – Nybble

16

Loại tồn tại hoạt động một cách tỉ mỉ hơn các loại thông thường. GHC là (đúng) cấm bạn sử dụng theA làm chức năng. Nhưng hãy tưởng tượng không có lệnh cấm như vậy. Loại chức năng đó sẽ có? Nó sẽ phải là cái gì đó như thế này:

-- Not a real type signature! 
theA :: ALL -> t -- for a fresh type t on each use of theA; t is an instance of Show 

Nói một cách rất thô sơ, forall làm GHC "quên" các loại của các đối số của constructor; tất cả những gì hệ thống kiểu biết là loại này là một thể hiện của Show. Vì vậy, khi bạn cố gắng trích xuất giá trị của đối số của hàm tạo, không có cách nào để khôi phục kiểu gốc.

GHC làm gì, đằng sau hậu trường, là nhận xét về chữ ký giả mạo ở trên, mỗi lần bạn khớp mẫu với hàm tạo ALL, biến được gắn với giá trị của hàm tạo được gán một kiểu duy nhất đảm bảo khác với mọi loại khác. Lấy ví dụ mã này:

case ALL "foo" of 
    ALL x -> show x 

Biến x được một loại duy nhất là khác biệt với tất cả các loại khác trong chương trình và không thể phù hợp với bất kỳ loại biến. Các kiểu duy nhất này không được phép thoát ra khỏi mức cao nhất - đó là lý do tại sao không thể sử dụng theA làm hàm.

+5

Nói chung, bạn có thể nghĩ về một kiểu tồn tại như một bộ phụ thuộc, trong đó phần tử đầu tiên là một kiểu ('*') và phần tử thứ hai là một giá trị kiểu đó - 'Σ [a: *] a'. Vấn đề là, khi bạn cố gắng viết chữ ký kiểu cho phép chiếu phần tử thứ hai của bộ tuple, bạn cần phải biết giá trị của phần tử đầu tiên. Điều này không thể được thể hiện trong Haskell. Nếu bạn đã gõ ngôn ngữ phụ thuộc, bạn có thể viết nó như (sử dụng ký pháp Agda): '(x: Σ [a: *] a) → fst x'. – Vitus

+4

+1 Điều này giải thích thông báo lỗi "Không thể sử dụng công cụ chọn bản ghi' theA 'làm hàm ** do biến loại đã thoát ** " –