2009-04-27 23 views
59

Tôi mới dùng Haskell và phải đối mặt với lỗi "không thể xây dựng loại vô hạn" mà tôi không thể hiểu được. Trong thực tế, ngoài ra, tôi đã không thể tìm thấy một lời giải thích tốt về những gì lỗi này thậm chí có nghĩa là, vì vậy nếu bạn có thể vượt ra ngoài câu hỏi cơ bản của tôi và giải thích lỗi "loại vô hạn", tôi thực sự đánh giá cao nó.Tại sao mã Haskell này tạo ra lỗi "loại vô hạn"?

Dưới đây là các mã:

intersperse :: a -> [[a]] -> [a] 

-- intersperse '*' ["foo","bar","baz","quux"] 
-- should produce the following: 
-- "foo*bar*baz*quux" 

-- intersperse -99 [ [1,2,3],[4,5,6],[7,8,9]] 
-- should produce the following: 
-- [1,2,3,-99,4,5,6,-99,7,8,9] 

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:y:xs) = x:s:y:intersperse s xs 

Và đây là lỗi khi cố gắng tải nó vào người phiên dịch:

Prelude> :load ./chapter.3.ending.real.world.haskell.exercises.hs 
[1 of 1] Compiling Main (chapter.3.ending.real.world.haskell.exercises.hs, interpreted) 

chapter.3.ending.real.world.haskell.exercises.hs:147:0: 
Occurs check: cannot construct the infinite type: a = [a] 
When generalising the type(s) for `intersperse' 
Failed, modules loaded: none. 

Cảm ơn.

-

Dưới đây là một số điều chỉnh mã và một hướng dẫn chung để đối phó với các lỗi "loại vô hạn" trong Haskell:

Corrected đang

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:xs) = x ++ s:intersperse s xs 

gì vấn đề là:

Trạng thái chữ ký loại của tôi s mà tham số thứ hai để phân tách là danh sách các danh sách . Do đó, khi mẫu của tôi khớp với "s (x: y: xs)", x và y đã trở thành danh sách. Tuy nhiên, tôi đã xử lý x và y là yếu tố, không phải danh sách.

Hướng dẫn để đối phó với các "loại vô hạn" lỗi:

Hầu hết thời gian, khi bạn nhận được lỗi này, bạn đã quên các loại của các biến khác nhau mà bạn đang làm việc với, và bạn đã cố gắng sử dụng một biến như thể nó là một số loại khác hơn so với những gì nó được. Hãy xem xét kỹ mọi thứ về loại nào so với cách bạn sử dụng nó và điều này thường sẽ phát hiện ra vấn đề.

+1

Một mẹo hay khác: khai báo các loại một cách rõ ràng. Điều này mang lại cho trình biên dịch một cái gì đó để kiểm tra. –

+1

Vì vậy, điều này giải quyết vấn đề, nhưng tại sao trình biên dịch nói "Không thể xây dựng kiểu vô hạn?". Điều đó nghĩa là gì? Nếu vấn đề là bạn đang cố gắng thực hiện các thao tác trên các kiểu không hỗ trợ các hoạt động đó, tại sao trình biên dịch lại không nói như vậy? – freedrull

+9

+1 cho cấu trúc của câu hỏi (câu hỏi - đã sửa - vấn đề là - hướng dẫn) – Dacav

Trả lời

27

Vấn đề nằm trong mệnh đề cuối cùng, nơi bạn coi x và y là phần tử, trong khi đó là các danh sách. Điều này sẽ làm việc:

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:y:xs) = x ++ [s] ++ y ++ intersperse s xs 

Lỗi loại vô hạn xảy ra vì: nhà điều hành có kiểu a -> [a] -> [a], trong khi bạn đối xử với nó như [a] -> a -> [a] , có nghĩa là [a] phải được xác định bằng a, có nghĩa là a là một danh sách lồng nhau vô hạn. Điều đó là không được phép (và không phải những gì bạn có nghĩa là, anyway).

Chỉnh sửa: cũng có một lỗi khác trong mã ở trên. Nó phải là:

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs 
+0

Cảm ơn. Tôi đã tìm ra cả hai thứ đó và sau đó quay lại đây và thấy câu trả lời của bạn, đó là sự xác minh tuyệt vời cho tôi. Bạn cũng sửa lỗi của tôi tốt hơn tôi đã làm. Lỗi của tôi là nó đã bỏ qua một dấu phân cách giữa y và xs. Để khắc phục nó, tôi đã giới thiệu một mức phù hợp với mẫu khác, như sau: intersperse s (x: y: []) = x ++ s: y intersperse s (x: y: xs) = intersperse s [x, y] ++ s: intersperse s xs Nhưng có vẻ như bạn đã sửa lỗi của mình mà không cần thêm cấp độ đó. –

+1

Đây là bài học tôi học: "Khi đối mặt với lỗi" loại vô hạn ", bạn có thể quên những loại bạn đang xử lý và do đó làm điều gì đó bạn không có ý định làm. Hãy xem kỹ loại nào của bạn biến là, và điều đó thường sẽ phát hiện ra vấn đề. " Có điều gì bạn sẽ thêm hoặc thay đổi trong đó không? –

+0

Điều đó chắc chắn đúng, và tôi sẽ không thay đổi gì trong đó.Các loại vô hạn không được phép, và do đó một loại lỗi vô hạn có nghĩa là một nơi nào đó một hàm nhận được một đối số với một kiểu không chính xác. Chúc may mắn với RWH :) – Stephan202

2

Tôi có thể sai, nhưng có vẻ như bạn đang cố gắng giải quyết một vấn đề khó khăn hơn. Phiên bản intersperse của bạn không chỉ làm tăng giá trị với mảng mà còn làm phẳng nó một cấp.

Mô-đun List trong Haskell thực sự cung cấp chức năng giao nhau. Giá trị đặt trong giá trị được đưa ra giữa mỗi phần tử trong danh sách.Ví dụ:

intersperse 11 [1, 3, 5, 7, 9] = [1, 11, 3, 11, 5, 11, 7, 11, 9] 
intersperse "*" ["foo","bar","baz","quux"] = ["foo", "*", "bar", "*", "baz", "*", "quux"] 

Tôi giả định đây là những gì bạn muốn làm bởi vì đó là những gì giáo sư của tôi muốn chúng tôi làm khi tôi học Haskell. Tôi có thể, tất nhiên, là hoàn toàn ra ngoài.

+0

Cảm ơn bạn đã bình luận. Trong trường hợp này, mặc dù, tôi muốn san bằng nó một cấp độ, bởi vì tôi đang tập thể dục 7 từ cuối Chương 3 của "Real World Haskell". –

+0

Gotcha. Nếu tôi có cuốn sách, tôi sẽ kiểm tra trước khi tôi viết. Than ôi, tất cả những gì tôi có thể làm là đoán. Vui mừng bạn đã nhận nó được sắp xếp anyway. :-) –

+4

Nội dung của cuốn sách được tạo sẵn trực tuyến miễn phí: http://book.realworldhaskell.org/ – Stephan202

0

Tôi cũng tìm thấy this giải thích ý nghĩa của lỗi.

Mỗi lần trình thông dịch/trình biên dịch cho tôi lỗi này là vì tôi đang sử dụng một số tham số kiểu tham số chính thức. Mọi thứ hoạt động chính xác bằng cách xóa định nghĩa kiểu của hàm, có chứa biến kiểu.

Tôi vẫn không thể tìm ra cách sửa lỗi và giữ định nghĩa loại chức năng.

3

Thường thêm định nghĩa kiểu rõ ràng có thể làm cho thông báo lỗi loại trình biên dịch trở nên có ý nghĩa hơn. Nhưng trong trường hợp này, việc đánh máy rõ ràng làm cho thông báo lỗi của trình biên dịch tồi tệ hơn.

Hãy xem những gì sẽ xảy ra khi tôi để GHC đoán loại vãi ra:

Occurs check: cannot construct the infinite type: a = [a] 
    Expected type: [a] -> [[a]] -> [[a]] 
    Inferred type: [a] -> [[a]] -> [a] 
In the second argument of `(:)', namely `intersperse s xs' 
In the second argument of `(:)', namely `y : intersperse s xs' 

Đó chỉ rõ ràng đối với các lỗi trong mã. Sử dụng kỹ thuật này, bạn không phải nhìn chằm chằm vào mọi thứ và suy nghĩ kỹ về các loại, như những người khác đã đề nghị làm.

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