2011-08-16 39 views
12

Tôi đã đi sâu vào gritty nitty của hệ thống kiểu haskell và cố gắng để có được điểm tốt của các lớp kiểu. Tôi đã học được một đống, nhưng tôi đánh một bức tường trên các đoạn mã sau đây.Các kiểu hệ thống kiểu Haskell

Sử dụng những Class và thẩm định nghĩa:

class Show a => C a where 
    f :: Int -> a 

instance C Integer where 
    f x = 1 

instance C Char where 
    f x = if x < 10 then 'c' else 'd' 

Tại sao nó rằng đây vượt qua kiểm tra loại:

nhưng điều này không?

g :: C a => a -> Int -> String 
g x y = show(f y) 

Tôi tìm thấy giải pháp thay thế thứ hai dễ đọc hơn và dường như chỉ khác biệt nhỏ (lưu ý chữ ký kiểu). Tuy nhiên, cố gắng để có được điều đó trong quá khứ typechecker kết quả trong:

*Main> :l typetests.hs 
[1 of 1] Compiling Main    (typetests.hs, interpreted) 

typetests.hs:11:14: 
    Ambiguous type variable `a0' in the constraints: 
     (C a0) arising from a use of `f' at typetests.hs:11:14 
     (Show a0) arising from a use of `show' at typetests.hs:11:9-12 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the first argument of `show', namely `(f y)' 
    In the expression: show (f y) 
    In an equation for `g': g x y = show (f y) 
Failed, modules loaded: none. 

Và tôi không hiểu tại sao.

Lưu ý: Vui lòng không hỏi "Bạn đang cố gắng làm gì?" Tôi hy vọng điều hiển nhiên là tôi chỉ rối tung trong một bối cảnh trừu tượng để thăm dò cách ngôn ngữ này hoạt động. Tôi không có mục tiêu trong tâm trí khác ngoài việc học một cái gì đó mới.

Cảm ơn

+3

Địa ngục đẫm máu! Bài đầu tiên trên SO và tôi nhận được ba câu trả lời tuyệt vời và sâu sắc trong chưa đầy 24 giờ. Nơi này thật tuyệt vời. Cảm ơn các bạn – TheIronKnuckle

Trả lời

21

Đây là nơi đồ chơi vui nhộn được phát. Xem xét hàm Prelude chuẩn asTypeOf.

asTypeOf :: a -> a -> a 
asTypeOf = const 

Nó chỉ trả về đối số đầu tiên, bất kể đối số thứ hai là gì. Nhưng chữ ký kiểu trên nó đặt ràng buộc bổ sung là cả hai đối số của nó phải cùng loại.

g :: C a => a -> Int -> String 
g x y = show (f y `asTypeOf` x) 

Hiện tại, GHC biết loại f y là gì. Nó giống như loại đối số đầu tiên cho g. Nếu không có thông tin đó, bạn sẽ nhận được thông báo lỗi mà bạn thấy. Không có đủ thông tin để xác định loại f y. Và bởi vì loại này là quan trọng (nó được sử dụng để xác định cá thể nào sử dụng cho show), GHC cần phải biết bạn có ý nghĩa gì khi tạo mã.

16

Trong

g :: C a => a -> Int -> a 
g x y = f y 

kiểu trả về của f y được cố định bởi chữ ký loại, do đó nếu bạn gọi, ví dụ g 'a' 3, instance C Char sẽ được sử dụng. Nhưng trong

g :: C a => a -> Int -> String 
g x y = show(f y) 

có hai hạn chế về kiểu trả về của f: nó phải là một thể hiện của C (để f có thể được sử dụng) và Show (để show có thể được sử dụng). Và đó là tất cả! Sự trùng hợp của tên biến kiểu a trong định nghĩa của fg không có nghĩa là bất cứ điều gì. Vì vậy, trình biên dịch không có cách nào để lựa chọn giữa instance C Charinstance C Integer (hoặc bất kỳ trường hợp nào được xác định trong các mô-đun khác, do đó việc xóa các trường hợp này sẽ không làm cho chương trình biên dịch).

21

Đây là biến thể của sự cố khét tiếng show . read. Phiên bản cổ điển sử dụng

read :: Read a => String -> a 
show :: Show a => a -> String 

nên thành phần có vẻ là một đồng bằng cũ Chuỗi dò

moo :: String -> String 
moo = show . read 

ngoại trừ việc không có thông tin trong chương trình để xác định loại ở giữa, do đó những gì để read và sau đó show.

Ambiguous type variable `b' in the constraints: 
    `Read b' arising from a use of `read' at ... 
    `Show b' arising from a use of `show' at ... 
Probable fix: add a type signature that fixes these type variable(s) 

Xin vui lòng không ghci đó làm một loạt các mặc định thêm điên, giải quyết sự mơ hồ tùy ý.

> (show . read) "()" 
"()" 

lớp C của bạn là một biến thể của Read, ngoại trừ việc nó giải mã một Int thay vì đọc một String, nhưng vấn đề cơ bản là như nhau.

Loại người đam mê hệ thống sẽ lưu ý rằng các biến loại không bị giới hạn không phải là mỗi se một vấn đề lớn. Đó là mơ hồ thể hiện suy luận đó là vấn đề ở đây. Cân nhắc

poo :: String -> a -> a 
poo _ = id 

qoo :: (a -> a) -> String 
qoo _ = "" 

roo :: String -> String 
roo = qoo . poo 

Trong việc xây dựng roo, nó không bao giờ xác định những gì các loại ở giữa phải, cũng không phải là roo đa hình trong loại đó. Loại suy luận không giải quyết cũng không generalizes biến! Mặc dù vậy,

> roo "magoo" 
"" 

nó không phải là một vấn đề, bởi vì việc xây dựng là tham số trong các loại chưa biết. Thực tế là loại không thể được xác định có kết quả là loại không thể vấn đề.

Nhưng không rõ trường hợp rõ ràng là vấn đề. Kết quả đầy đủ cho suy luận kiểu Hindley-Milner dựa trên tham số và do đó bị mất khi chúng ta thêm quá tải. Hãy để chúng tôi không khóc cho nó.

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