2012-02-04 27 views
7

Tôi bắt đầu nghiên cứu Haskell một tuần trước và có một vấn đề lạ. Tôi đã tạo một kiểu dữ liệu đơn giản và muốn hiển thị nó trong một bảng điều khiển. Tôi đã tạo 2 hàm cho 2 hàm tạo của kiểu của tôi. Trình biên dịch có thể gọi hàm nếu tôi sử dụng một hàm tạo với 2 đối số. Nhưng nó không thể gọi một chức năng khác mà nên bắt một nhà xây dựng với 1 đối số.Chức năng cho các nhà xây dựng dữ liệu khác nhau

module Main (
    main 
) where 

data MyContainter a b = FirstVersion a b 
        | SecondVersion a 
        deriving(Show,Eq) 

showContainer (FirstVersion a b) = show b 
showContainer (SecondVersion a) = show a 

--startF = showContainer (FirstVersion 1 2) -- it works 
startF = showContainer (SecondVersion 1) -- it doesn't work 

main = putStr startF 

Các trình biên dịch nói:

Ambiguous type variable `a0' in the constraint: 
    (Show a0) arising from a use of `showMaybe' 
Probable fix: add a type signature that fixes these type variable(s) 
In the expression: showMaybe (SecondVersion 1) 
In an equation for `startF': startF = showMaybe (SecondVersion 1) 

Tại sao nó lại nói vậy? Tôi tạo ra (SecondVersion 1) trực tiếp và không hiểu tại sao trình biên dịch không gọi showContainer (SecondVersion a).

+0

Nó giúp nhận ra rằng biến kiểu 'a0' trong thông báo lỗi giống như' b', và không liên quan gì đến 'a'. (Trình biên dịch vừa xảy ra để chọn tên đó vì lớp 'Show' sử dụng tên' a'). – hammar

Trả lời

9

Vấn đề là showContainer có các loại:

showContainer :: (Show a, Show b) => MyContainer a b -> String 

Nhưng khi bạn vượt qua SecondVersion 1, nó không biết b là gì, vì SecondVersion 1 công trình cho bất kỳ loại b! Khi bạn vượt qua một FirstVersion, nó hoạt động tốt, bởi vì, như FirstVersion chứa cả một số ab, không bao giờ có bất kỳ sự mơ hồ nào về những gì chúng cần.

Vì vậy, kể từ khi biên dịch không có cách nào để biết những gì bạn b muốn, và không có cách nào để biết rằng sự lựa chọn của b không ảnh hưởng đến showContainer (sau khi tất cả, nó không ảnh hưởng đến hành vi khi bạn vượt qua FirstVersion, vì nó sử dụng show trên một giá trị loại b), nó từ bỏ.

Đó là những gì thông báo lỗi nói: biến loại a0 không rõ ràng, vì vậy vui lòng thêm chữ ký loại để cho tôi biết đó là gì. Trong trường hợp này, nó không quan trọng nó là gì, vì vậy bạn chỉ có thể thiết lập nó để ():

startF = showContainer (SecondVersion 1 :: MyContainer Integer()) 

Bạn có thể sẽ không chạy vào các lỗi như thế này rất thường xuyên, vì bối cảnh mà bạn sử dụng các giá trị trong thường sẽ buộc phải sử dụng b cụ thể.

GHC không phải là tốt nhất trong việc chọn biến loại, thật không may; nếu bạn đã cho showContainer chữ ký kiểu chữ rõ ràng như tôi đã hiển thị, thì nó cũng sẽ sử dụng b trong thông báo lỗi.

+0

Cảm ơn, đó là mô tả hay) – Alexey

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