2012-01-05 53 views
34

Tôi đang làm việc trên 99 câu hỏi Haskell và thấy một giải pháp cho việc tìm kiếm các yếu tố cuối cùng của một danh sách:hành vi của "id const"

myLast = foldr1 (const id) 

loại consta -> b -> a nhưng đó của const idb -> a -> a
vậy ma thuật ở đây là gì?

+0

Chỉ để bổ sung các câu trả lời được cung cấp, hãy nhớ rằng tất cả các hàm trong Haskell đều được curried, vì vậy 'a -> (b -> c)' giống với 'a -> b -> c' –

+0

Có một [câu hỏi tương tự ] (http://stackoverflow.com/questions/18680341/what-is-the-purpose-of-const-id-in-this-function), nhưng nó có một câu trả lời tình huống hơn, có thể rõ ràng hơn, tùy thuộc vào quá trình suy nghĩ của bạn. – chwarr

Trả lời

42

Loại idc->c; nó chỉ trả lại cùng một điều nó được đưa ra.

Loại consta->b->a. Trong const id, a trở thành c->c, vì vậy các loại const trong trường hợp này trở thành:

(c->c) -> b -> (c->c) 

Bây giờ bạn đã áp dụng chức năng const này, nghĩa là bạn đã trôi qua id với nó, sau đó bạn là trái với b -> (c->c).

PS: Loại const const ida->b->a, và loại const const const idb->a->a, và như vậy!

+0

mát mẻ, sự kỳ diệu của hai hàm đơn giản – manuzhang

+0

Không có gì lạ, như 'const foo bar = foo'. Cũng lưu ý rằng 'const id' cũng giống như' flip const', hoặc 'flip const lật const lật const lật const id id id';) –

+3

Ngoài ra' id = ap const const'. – augustss

23

Không có phép thuật. Định nghĩa của const là:

const :: a -> b -> a 
const x y = x 

Và định nghĩa của id là:

id :: a -> a 
id x = x 

Vì vậy const id chỉ là \y -> id, một hàm luôn trả về id. Và nếu id chỉ là \x -> x thì const id phải giống như \y -> \x -> x. Ergo, nó có loại b -> (a -> a).

const id cũng có thể được viết flip const. Kể từ const\x -> \y -> x, sau đó flip const lấy các đối số theo thứ tự ngược lại, \y -> \x -> x, giống như const id.

6

Đây là sự hiểu biết của tôi về cách thức hoạt động.

Đây là giải thích đơn giản nhất mà tôi có thể nghĩ đến, tôi đã cố gắng (cố ý) để tránh bất kỳ khái niệm hay từ ngữ nào có thể gây nhầm lẫn.

Một khái niệm quan trọng cần lưu ý là ứng dụng một phần. Cách tôi hiểu điều này là, trong Haskell, chúng ta có thể "sửa" một trong các tham số của hàm thành một giá trị đã biết, do đó, bây giờ hàm chấp nhận một tham số ít hơn.

Tóm tắt: loại const là:

const :: a -> b -> a 

Như một ví dụ đơn giản, chúng ta hãy “sửa chữa” các tham số đầu tiên là (+)

let f = const (+) 

Bây giờ chúng ta đã khắc phục các tham số đầu tiên của const, “f” là một hàm chỉ chấp nhận một tham số duy nhất. Nhưng vì const luôn trả về tham số đầu tiên mà chúng ta đã sửa, có nghĩa là bất cứ điều gì chúng ta chuyển tới “f” sẽ bị bỏ qua, và nó sẽ luôn trả về hàm “+”.

Ví dụ, tất cả những điều sau đây sẽ cung cấp cho 5, vì e sẽ luôn trả lại chức năng “+” bất kể những gì nó nhận được là tham số đầu tiên, và chức năng “+” sẽ hoạt động trên 2 và 3:

f “aaa”  2 3 
f 904212  2 3 
f undefined 2 3 

loại f là:

f :: b -> Integer -> Integer -> Integer 

Lưu ý rằng “b” có thể là bất cứ điều gì, như có thể thấy ở trên.

Bây giờ cho các chức năng thực tế trong câu hỏi:

g = const id 

Điều này có nghĩa rằng chúng ta “cố định” id như tham số đầu tiên, do như trên, “g” bỏ qua tham số đầu tiên của nó và trả về chức năng “id” . Trong Haskell, chúng ta có thể đi về phía trước và cung cấp các tham số thêm để “id”, giống như chúng tôi đã làm cho (+) ở trên, ví dụ như vậy tất cả trong số này sẽ quay trở lại 42:

g “aaa”  42 
g undefined 42 

Vì vậy, “g” được chức năng chấp nhận hai tham số, và luôn luôn trả lại một giây, vì vậy loại của nó là:

g = const id :: b -> a -> a 

Nhưng chờ một phút, tôi chỉ cần thực hiện một bước nhảy vọt khổng lồ đó. Loại không phải là:

b -> (a -> a) 

vì chúng tôi vừa nói rằng chúng tôi chấp nhận bất kỳ điều gì và trả về "id"?

Vâng, vâng, ngoại trừ trong Haskell những dấu ngoặc đơn đó có thể được bỏ qua.
Nó cũng có ý nghĩa vì bạn có thể cung cấp ngay chức năng “id” với tham số phụ cần thiết (như trong ví dụ “const (+)” ở trên).

1

Cách duy nhất cuối cùng tôi nắm bắt được điều này là tưởng tượng trình tự các bước mà Haskell thực hiện trong việc đánh giá biểu thức như const id 1 2. Đầu tiên xem xét các báo cáo:

Trong Haskell, tất cả các chức năng được coi là cà ri: Đó là, tất cả các chức năng trong Haskell chỉ mất một đối số. 1

Ứng dụng chức năng, liên kết ở bên trái: f x y thực sự là (f x) y.1

Với điều này trong tâm trí, và nhìn thấy từ trên cao const mà phải mất hai đối số và id mất một, chúng ta có thể thấy các bước sau:

const id 1 2 -- Haskell evaluates 'const id' and returns a function (we can call it 
       -- 'constId') which accepts one argument and always returns 'id' 

constId 1 2 -- Haskell now evaluates 'constId 1', which as expected just returns 'id' 

id 2   -- 'id' is now applied to 2, which just returns '2' 

2    -- final result 

Disclaimer: Tôi mới vào Haskell.