2016-12-08 20 views
27

Sử dụng định nghĩa sau đây:hành vi mâu thuẫn của những Lambda Chức năng

lenDigits n = length (show n) 
factorial n = product [1..n] 

tôi đánh giá sau

Prelude> ((lenDigits . factorial) 199) <= 199 
False 
Prelude> (\i -> ((lenDigits . factorial) i) <= i) 199 
True 

lý do cho hành vi như vậy là gì? Như tôi thấy, biểu thức đầu tiên cũng giống như biểu thức thứ hai với lambdas giảm.

+5

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. –

+0

@DanielWagner Tại sao điều này lại xảy ra? Không phải là 'id' đa hình? –

+3

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. –

Trả lời

25

Vì trong biểu thức đầu tiên, 199 đầu tiên có loại Integer và thứ hai có Int. Nhưng trong biểu thức thứ hai đều có loại Intfactorial 199 không thể được thể hiện bằng loại Int.

+1

Điều này có liên quan đến hạn chế monomorphism? – mnoronha

+14

Tôi không nghĩ vậy. Trong ví dụ đầu tiên, 199 đầu tiên được tự do mặc định là 'Integer', nhưng cái thứ hai buộc phải được coi là' Int' vì nó được so sánh với giá trị trả về của 'lenDigits'. Trong lần thứ hai, 'i' bị buộc phải là' Int' với cùng lý do, và lần lượt buộc 199 là một 'Int'. – chepner

+1

@chepner Có, bạn đúng! – freestyle

8

Ở đâ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 => aNum b => b, nếu bạn muốn).

lenDigitsShow 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 (<=)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 
Các vấn đề liên quan