2015-07-19 13 views
10

Trong khi làm một số bài tập trong GHCi tôi đánh máy và nhận được những điều sau>biểu với kiểu Num Strange Haskell ([Char] -> t) => t

ghci> (1 "one") 

<interactive>:187:1: 
    No instance for (Num ([Char] -> a0)) arising from a use of ‘it’ 
    In a stmt of an interactive GHCi command: print it 

đó là một lỗi, howeve nếu tôi hỏi GHCi đối với loại biểu thức, nó không cung cấp bất kỳ lỗi nào:

ghci> :type (1 "one") 
(1 "one") :: Num ([Char] -> t) => t 

Ý nghĩa của (1 "one") là gì?

Tại sao cụm từ này đưa ra lỗi, nhưng GHCi cho biết nó được nhập tốt?

Ý nghĩa của Num ([Char] -> t) => t là gì?

Cảm ơn.

+1

Hãy nhớ rằng không gian là toán tử ứng dụng hàm. – Bergi

Trả lời

10

Báo cáo Haskell để giải cứu! (Trích dẫn section 6.4.1)

An integer literal represents the application of the function fromInteger to the appropriate value of type Integer.

fromInteger có kiểu:

Prelude> :t fromInteger 
fromInteger :: Num a => Integer -> a 

Vì vậy 1 thực sự là đường cú pháp cho fromInteger (1 :: Integer). biểu hiện của bạn, sau đó, là:

fromInteger 1 "one" 

Mà có thể được viết như sau:

(fromInteger 1) "one" 

Bây giờ, fromInteger tạo ra một số (có nghĩa là, một giá trị của một loại mà là một thể hiện của Num, như loại của nó cho chúng ta biết). Trong biểu thức của bạn, số này được áp dụng cho một số [Char] (chuỗi "one"). GHC kết hợp một cách chính xác hai mảnh những thông tin để suy luận rằng biểu hiện của bạn có gõ:

Num ([Char] -> t) => t 

Nghĩa là, nó sẽ là kết quả (loại không xác định t) của việc áp dụng một chức năng mà còn là một Num đến một [Char]. Đó là một loại hợp lệ về nguyên tắc. Vấn đề duy nhất là không có trường hợp của Num cho [Char] -> t (có nghĩa là, chức năng mà có dây không phải là con số, mà không phải là đáng ngạc nhiên).

P.S .: Như Sibi và Ørjan chỉ ra, trong GHC 7.10 và sau đó bạn sẽ chỉ thấy lỗi được đề cập trong câu hỏi nếu mở rộng FlexibleContexts GHC; nếu không, trình kiểm tra kiểu thay vào đó sẽ khiếu nại về việc có các kiểu cố định và các hàm tạo kiểu trong ràng buộc lớp (nghĩa là, Char, [](->)).

+1

Câu trả lời hay. Ngoài ra, nếu bạn muốn đánh máy trong 'ghci', nó có thể được thực hiện bằng cách bật phần mở rộng ngữ cảnh' FlexibleContexts'. 'let x = 1" một "' và ': t x' sẽ cho bạn thấy cùng một loại trong' ghci'. – Sibi

+0

Tôi không nghĩ rằng câu hỏi là giả định rằng phần mở rộng GHC 'FlexibleContexts' được bật. Kiểu ': t (1" một ")' hoạt động mà không cho phép phần mở rộng đó không phải là một hành vi nhất quán của ghci IMO. – Sibi

+0

@Sibi Thật vậy. Tuy nhiên, lỗi không có thay đổi ': t' nếu bạn không bật' FlexibleContexts'. – duplode

1

TL; DR: Đó là một loại vô nghĩa bị cắt xén không đáng lo ngại.

Các chữ số nguyên có thể đại diện cho các giá trị của bất kỳ loại nào thực hiện các kiểu chữ Num. Vì vậy, 1 hoặc bất kỳ chữ số nguyên nào khác có thể được sử dụng ở bất cứ nơi nào bạn cần một số.

doubleVal :: Double 
doubleVal = 1 

intVal :: Int 
intVal = 1 

integerVal :: Integer 
integerVal = 1 

Điều này cho phép chúng tôi sử dụng linh hoạt các chữ số nguyên trong bất kỳ ngữ cảnh số nào.

Khi bạn chỉ sử dụng một chữ số nguyên mà không có bất kỳ ngữ cảnh kiểu nào, ghci không biết loại đó là gì.

Prelude> :type 1 
1 :: Num a => a 

ghci đang nói "rằng '1' là của một số loại I không biết, nhưng tôi biết rằng bất cứ loại đó là, loại mà thực hiện các typeclass Num".

Mỗi lần xuất hiện của một chữ số nguyên trong nguồn Haskell được bao bọc với hàm ẩn fromInteger. Vì vậy, (1 "one") được chuyển đổi hoàn toàn thành ((fromInteger (1::Integer)) "one") và subexpression (fromInteger (1::Integer)) có một loại chưa biết Num a => a, một lần nữa có nghĩa là đó là một số loại không xác định, nhưng chúng tôi biết nó cung cấp một thể hiện của typeclass Num.

Chúng tôi cũng có thể thấy rằng nó được áp dụng như một hàm số "one", vì vậy chúng tôi biết rằng loại của nó phải có dạng [Char] -> a0 trong đó a0 là một loại không xác định khác. Vì vậy, a[Char] -> a0 phải giống nhau. Thay thế trở lại loại Num a => a mà chúng tôi đã tìm ra ở trên, chúng tôi biết rằng 1 phải có loại Num ([Char] -> a0) => [Char] -> a0) và biểu thức (1 "one") có loại Num ([Char] -> a0) => a0. Đọc loại cuối cùng là "Có một số loại a0 là kết quả của việc áp dụng đối số [Char] cho hàm và loại chức năng đó là một thể hiện của lớp Num.

Vì vậy, biểu thức có một loại hợp lệ Num ([Char] -> a0) => a0.

Haskell có tên gọi là Monomorphism restriction.Một khía cạnh của điều này là tất cả các biến kiểu trong biểu thức phải có một loại đã biết cụ thể trước khi bạn có thể đánh giá chúng. Tuy nhiên, GHC không biết bất kỳ loại a0 nó có thể cắm vào biểu thức loại ở trên có một ví dụ Num được định nghĩa. t không có cách nào để đối phó với nó, và cung cấp cho bạn thông báo "No Instance for Num ...".

+1

Chắc chắn * không * một 'loại vô nghĩa bị cắt xén'. Tại sao bạn nói rằng trong tl của bạn, dr? – AJFarmar

+0

Bạn có coi loại đó hữu ích và có ý nghĩa không? – NovaDenizen

+0

@NovaDenizen Có! Ví dụ: xem câu trả lời của tôi ở đây - http://stackoverflow.com/questions/32443925/haskell-weird-expression/32444024#32444024 –

3

Haskell là một ngôn ngữ rất linh hoạt, nhưng cũng rất hợp lý hợp lý theo nghĩa đen. Vì vậy, thông thường, hầu hết các ngôn ngữ sẽ là lỗi cú pháp, Haskell sẽ xem xét chúng và thử nghiệm nó một cách rõ ràng để hiểu được chúng, với kết quả thực sự khó hiểu nhưng thực sự chỉ là hậu quả logic của các quy tắc của ngôn ngữ.

Ví dụ, nếu chúng ta gõ ví dụ của bạn vào Python, nó về cơ bản cho chúng ta biết "những gì bạn vừa gõ vào làm cho không có ý nghĩa":

Python 2.7.6 (default, Sep 9 2014, 15:04:36) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> (1 "one") 
    File "<stdin>", line 1 
    (1 "one") 
     ^
SyntaxError: invalid syntax 

của Ruby làm điều tương tự:

irb(main):001:0> (1 "one") 
SyntaxError: (irb):1: syntax error, unexpected tSTRING_BEG, expecting ')' 
(1 "one") 
    ^
    from /usr/bin/irb:12:in `<main>' 

Nhưng Haskell không từ bỏ điều đó một cách dễ dàng! Nó thấy (1 "one"), và nó lý do mà:

  • Expressions có dạng f xứng dụng chức năng, nơi f đã gõ như a -> b, x có kiểu af x có kiểu b.
  • Vì vậy, trong biểu thức 1 "one", 1 phải là hàm lấy "one" (một [Char]) làm đối số của nó.

Sau đó, cho phép xử lý chữ số của Haskell, nó dịch 1 thành fromInteger 1 :: Num b => [Char] -> b. fromInteger là phương pháp của lớp Num, có nghĩa là người dùng được phép cung cấp các triển khai của riêng nó cho bất kỳ loại nào — bao gồm [Char] -> b nếu bạn nghiêng. Vì vậy, các thông báo lỗi có nghĩa là Haskell, thay vì nói với bạn rằng những gì bạn gõ là vô nghĩa, nói với bạn rằng bạn đã không dạy nó làm thế nào để xây dựng một số loại Num b => [Char] -> b, bởi vì đó là điều thực sự kỳ lạ mà sẽ cần đúng với biểu thức có ý nghĩa.

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