Ở đây, hãy thực hiện theo từng bước về câu hỏi này.
Hãy bắt đầu với:
((lenDigits . factorial) 199) <= 199
Theo Haskell Report ...
Một số nguyên đen đại diện cho ứng dụng của hàm fromInteger
với giá trị thích hợp của loại Integer
.
Điều đó có nghĩa biểu hiện đầu tiên của chúng tôi là thực sự:
((lenDigits . factorial) (fromInteger (199 :: Integer))
<= (fromInteger (199 :: Integer))
Bằng cách riêng của mình, fromInteger (199 :: Integer)
có kiểu đa hình Num a => a
. Bây giờ chúng ta phải xem liệu kiểu này có chuyên biệt trong ngữ cảnh của toàn bộ biểu thức hay không. Lưu ý rằng, cho đến khi chúng tôi tìm thấy một lý do cho nó không được như vậy, chúng ta nên giả định rằng các loại đa hình của hai lần xuất hiện của fromInteger (199 :: Integer)
là độc lập (Num a => a
và Num b => b
, nếu bạn muốn).
lenDigits
là Show a => a -> Int
, và do đó ...
(lenDigits . factorial) (fromInteger (199 :: Integer))
... bên trái của <=
phải là một Int
. Cho rằng (<=)
là Ord a => a -> a -> Bool
, số fromInteger (199 :: Integer)
ở bên phải của <=
cũng phải là Int
. Toàn bộ biểu hiện sau đó trở thành:
((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (199 :: Int)
Trong khi thứ hai 199
được chuyên để Int
, người đầu tiên vẫn còn đa hình. Trong trường hợp không có chú thích loại khác, mặc định làm cho nó chuyên Integer
khi chúng tôi sử dụng biểu thức trong GHCi. Do đó, chúng tôi cuối cùng nhận được:
((lenDigits . factorial) (199 :: Integer)) <= (199 :: Int)
Bây giờ, trên để biểu thức thứ hai:
(\i -> ((lenDigits . factorial) i) <= i) 199
Bởi lý do tương tự sử dụng ở trên, (lenDigits . factorial) i
(bên trái của <=
) là một Int
, vv i
(ở bên phải của <=
) cũng là Int
.Đó là như vậy, chúng tôi có ...
GHCi> :t \i -> (lenDigits . factorial) i <= i
\i -> (lenDigits . factorial) i <= i :: Int -> Bool
... và do đó áp dụng nó để 199
(mà thực chất là fromInteger (199 :: Integer)
) chuyên nó sang int, cho:
((lenDigits . factorial) (199 :: Int)) <= (199 :: Int)
Các 199
đầu tiên tại là Int
thay vì Integer
. factorial (199 :: Int)
tràn kích thước cố định Int
loại, dẫn đến kết quả không có thật. Một cách để tránh điều đó sẽ được giới thiệu một rõ ràng fromInteger
để có được một cái gì đó tương đương với kịch bản đầu tiên:
GHCi> :t \i -> (lenDigits . factorial) i <= fromInteger i
\i -> (lenDigits . factorial) i <= fromInteger i :: Integer -> Bool
GHCi> (\i -> (lenDigits . factorial) i <= fromInteger i) 199
False
Bạn có thể cũng giống như so sánh hai, mà được bản chất của vấn đề, và tránh tất cả các thay đổi bất thường có typeclasses nằm xung quanh để gây nhầm lẫn mọi thứ: '(id đúng, id 'a')' là tốt nhưng '(\ f -> (f Đúng, f 'a')) id' là một lỗi. –
@DanielWagner Tại sao điều này lại xảy ra? Không phải là 'id' đa hình? –
Có thực sự, 'id' là đa hình; và '\ f -> ...' có thể đa hình; nhưng bên trong '...', 'f' chính nó là * không * đa hình! '\ f -> (f Đúng, f 'a')' đã là lỗi kiểu mà không nhắc đến 'id'. Hạn chế này được đưa ra để làm cho suy luận kiểu dễ dàng hơn và để bảo tồn tài sản mong muốn mà bất kỳ thuật ngữ nào có thể được cung cấp một loại nào đều có kiểu chung nhất. –