2012-02-28 31 views
5

Các kiểm tra kiểu chương trình sau đây nếu tôi xác định nó trên dòng lệnh (ví dụ ghci file.hs):ghci - biên dịch háo hức ở chế độ tương tác?

import Data.Ratio 
foo = let x = [1..] 
      y = (1%2) + (head x) 
     in y 

Tuy nhiên, nếu tôi nhập nó một cách tương tác, tôi sẽ nhận được một lỗi type:

Prelude> import Data.Ratio 
Prelude Data.Ratio> let x = [1..] 
Prelude Data.Ratio> let y = (1%2) + (head x) 
<interactive>:1:23: 
    Couldn't match expected type `Ratio a0' with actual type `Integer' 

Nó có vẻ như x đang được háo hức đánh máy là [Integer] trái ngược với tổng quát hơn (Num t, Enum t) => [t].

Tôi có thể làm gì về điều đó không? Có những tình huống khác trong đó chế độ tương tác sẽ khác với chế độ hàng loạt không?

+1

Hạn chế monomorphism ... – augustss

+1

và nhập mặc định – Ptival

+3

Thật vậy, đó là hạn chế monomorphism đáng sợ. Có hai cách xung quanh nó: cho chữ ký rõ ràng hoặc tắt hạn chế này (trong GHCi, bạn có thể làm ': set -XNoMonomorphismRestriction' và bạn đã hoàn thành; pragmas ngôn ngữ và cờ biên dịch cũng hoạt động). – Vitus

Trả lời

10

Bindings không có đối số, tức là những người có dạng x = ... này tùy thuộc vào monomorphism restriction, có nghĩa là GHC sẽ cố gắng làm cho nó không đa hình bằng cách sử dụng bất kỳ thông tin loại nào có sẵn và rơi trở lại trên type defaulting để giải quyết bất kỳ tham số nào iguities. (Trên thực tế, GHCi sử dụng a slightly more permissive set of defaulting rules, nhưng điều đó không thực sự quan trọng đối với câu hỏi này).

Vì không có thông tin loại khác có sẵn khi bạn viết let x = [1..], nhập mặc định khiến loại được suy ra là [Integer], vì Integer là loại số mặc định.

Có một số cách để giải quyết vấn đề này:

  1. Sử dụng chữ ký kiểu. Điều này luôn hoạt động, nhưng đôi khi có thể tẻ nhạt khi làm việc với các loại phức tạp.

    > let x = [1..] :: [Rational] 
    
  2. Viết kết buộc với đối số. Điều này không áp dụng trong trường hợp của bạn, nhưng đôi khi bạn thấy vấn đề này khi viết các định nghĩa hàm không có điểm.

    > let f = (+) 
    > :t f 
    f :: Integer -> Integer -> Integer 
    > let f x y = x + y 
    > :t f 
    f :: Num a => a -> a -> a 
    
  3. Cung cấp thêm thông tin cho người kiểm tra loại. Trong trường hợp của bạn, chúng tôi có thể tránh được sự cố bằng cách viết cả hai liên kết trong một tuyên bố let. Sau đó, GHC có thể sử dụng thông tin loại từ liên kết thứ hai để suy ra chính xác rằng x phải có loại [Rational].

    > let x = [1..]; y = 1%2 + head x 
    > :t x 
    x :: [Ratio Integer] 
    
  4. Tắt giới hạn đơn cấu hình. Điều này có thể có tác động nghiêm trọng về hiệu suất nếu bạn đang mong đợi loại thứ gì đó, ví dụ: một Integer, trong khi nó thực sự là một Num a => a, vì sau này phải được tính toán lại mỗi lần trong khi trước đó có thể được chia sẻ. Đây là lý do chính tại sao hạn chế tồn tại ở nơi đầu tiên.

    Tuy nhiên, trong thông dịch viên, điều này thường ít gây ra vấn đề hơn, vì vậy sự tiện lợi thường đáng giá.

    > :set -XNoMonomorphismRestriction 
    > let x = [1..] 
    > :t x 
    x :: (Num t, Enum t) => [t] 
    

    Nếu bạn muốn tùy chọn này theo mặc định, bạn có thể thêm số này vào .ghci file.

4

Bạn có thể làm điều gì đó về nó bằng cách định nghĩa x là như sau:

let x = [1..] :: [Ratio Int] 

như trong:

Data.Ratio Prelude> let x = [1..] :: [Ratio Int] 
Data.Ratio Prelude> let y = (1%2) + (head x) 
Data.Ratio Prelude> y 
3 % 2 
Data.Ratio Prelude> 
+1

Tôi khuyên bạn nên chống lại việc sử dụng 'Ratio Int', trừ khi bạn hoàn toàn tích cực biết rằng tính toán của bạn không thể tràn và bạn đang tuyệt vọng cho hiệu suất - và thậm chí sau đó tôi không thích nó. Theo tôi đó là một sai lầm tồi tệ khi làm cho 'Ratio' trở thành một loại đa hình, ngay cả những phép tính nhỏ có thể dễ dàng vượt quá 64 bit, và sau đó bạn hoàn toàn vô nghĩa. –

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