2012-05-06 36 views
5

Tôi tương đối mới với Haskell vì vậy xin lỗi nếu câu hỏi của tôi có vẻ ngu ngốc. Tôi đã cố gắng để hiểu cách thành phần chức năng hoạt động và tôi đã gặp một vấn đề mà tôi đã tự hỏi ai đó có thể giúp tôi. Tôi đang sử dụng bản đồ trong một hàm hợp trong hai tình huống sau:Haskell: Sử dụng bản đồ trong thành phần chức năng

  • map (*2) . filter even [1,2,3,4]
  • map (*2) . zipWith max [1,2] [4,5]

Mặc dù cả hai bộ lọc và chức năng zipWith trả về một danh sách, chỉ có thành phần đầu tiên hoạt động trong khi thứ hai thành phần ném lỗi dưới đây:

"Couldn't match expected type '[Int] -> [Int]' with actual type '[c0]' 

Mọi đề xuất sẽ được đánh giá cao.

+1

Câu trả lời cho [câu hỏi này] (http://stackoverflow.com/questions/2834626/haskell-dot-operator) có giúp được không? (Đặc biệt là [cái này] (http://stackoverflow.com/a/2834661/1256624)) – huon

+1

Cái đầu tiên thực sự tạo ra đầu ra 'Không thể khớp với kiểu mong đợi a0 -> [b0]' với kiểu thực [a1] '' –

Trả lời

5

Kết quả của zipWith max [1,2] [4,5] là danh sách chứ không phải chức năng. Toán tử (.) Yêu cầu một hàm làm toán hạng bên phải của nó. Do đó, lỗi trên dòng thứ hai của bạn. Có lẽ điều bạn muốn là

map (*2) (zipWith max [1,2] [4,5]) 

Ví dụ đầu tiên của bạn không biên dịch trên WinHugs (chế độ Hugs); nó có cùng lỗi. Sau đây sẽ làm việc

(map (*2) . filter even) [1,2,3,4] 

vì nó soạn hai hàm và áp dụng hàm kết quả cho đối số.

16

Hãy nhớ lại loại (.).

(.) :: (b -> c) -> (a -> b) -> a -> c 

Cần ba đối số: hai hàm và giá trị ban đầu và trả về kết quả của hai hàm được tạo.

Bây giờ, việc áp dụng hàm cho các đối số của nó liên kết chặt chẽ hơn toán tử (.). Vì vậy, biểu hiện của bạn:

map (*2) . filter even [1,2,3,4] 

được phân tách như:

(.) (map (*2)) (filter even [1,2,3,4]) 

bây giờ, đối số đầu tiên, map (*2) là ok. Nó có loại (b -> c), trong đó bcNum a => [a]. Tuy nhiên, số thứ hai là một danh sách duy nhất:

Prelude> :t filter even [1,2,3,4] 
filter even [1,2,3,4] :: Integral a => [a] 

và do đó kiểm tra loại sẽ phàn nàn rằng bạn đang đi qua một [a] như một cuộc tranh cãi khi (.) chức năng cần có một chức năng.

Và đó là những gì chúng ta thấy:

Couldn't match expected type `a0 -> [b0]' with actual type `[a1]' 
In the return type of a call of `filter' 
In the second argument of `(.)', namely `filter even [1, 2, 3, 4]' 
In the expression: map (* 2) . filter even [1, 2, 3, 4] 

... Vì vậy, parenthesization!

Hoặc sử dụng toán tử $ để thêm một dấu ngoặc:

map (*2) . filter even $ [1,2,3,4] 

hoặc sử dụng dấu ngoặc rõ ràng, loại bỏ các thành phần của hai chức năng

map (*2) (filter even [1,2,3,4]) 

hoặc thậm chí:

(map (*2) . filter even) [1,2,3,4] 
+0

cảm ơn Don. Điều đó thực sự hữu ích – wajeeh

+1

Nếu nó hữu ích, bạn nên chấp nhận câu trả lời của Don. – augustss

+1

Tôi biết rằng OP đã hỏi cụ thể về thành phần chức năng, nhưng ví dụ này thực sự phù hợp nhất để thẳng lên '$', _i.e._, 'map (* 2) $ filter thậm chí [1,2,3,4]' . – apc

4

Các các biểu mẫu sau hợp lệ:

map (* 2) $ filter even [1, 2, 3, 4] 
(map (* 2) . filter even) [1, 2, 3, 4] 
map (* 2) $ zipWith max [1, 2] [4, 5] 
(\xs -> map (* 2) . zipWith max xs) [1, 2] [4, 5] 

nhưng không phải như sau:

map (* 2) . filter even [1, 2, 3, 4] 
map (* 2) . zipWith max [1, 2] [4, 5] 
(map (* 2) . zipWith max) [1, 2] [4, 5] 

Tại sao lại như vậy? Vâng, lấy ví dụ

map (* 2) . zipWith max [1, 2] [4, 5] 

nó cũng giống như

(map (* 2)) . (((zipWith max) [1, 2]) [4, 5]) 

(map (* 2)) đã gõ [Int] -> [Int] (giả mặc định cho Int), (((zipWith max) [1, 2]) [4, 5]) có kiểu [Int](.) có kiểu (b -> c) -> (a -> b) -> a -> c hoặc ([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int] trong phi này trường hợp đa hình, do đó, điều này bị đánh máy. Mặt khác ($) có kiểu (a -> b) -> a -> b, hoặc ([Int] -> [Int]) -> [Int] -> [Int] trong trường hợp không đa hình này, vì vậy đây:

(map (* 2)) $ (((zipWith max) [1, 2]) [4, 5]) 

nổi gõ.

2

Do ưu tiên thấp của (.), Haskell phân tích

map (*2) . filter even [1,2,3,4] 

như

map (*2) . (filter even [1,2,3,4]) 

tức soạn map (*2) (một chức năng) với kết quả của filter even [1,2,3,4] (danh sách), mà làm cho không có ý nghĩa và là lỗi loại.

Bạn có thể sửa lỗi này bằng @ gợi ý Theodore, hoặc bằng cách sử dụng ($):

map (*2) . filter even $ [1,2,3,4] 
2

Nếu bạn kiểm tra các loại bản đồ đó là: (a -> b) -> [a] -> [b]

Vì vậy, phải mất một chức năng của một thành b và sau đó là danh sách a và trả về danh sách b. Đúng?

Bây giờ, bạn đã cung cấp chức năng của a thành b bằng cách chuyển tham số (*2). Vì vậy, chức năng bản đồ được áp dụng một phần của bạn sẽ là: [Integer] -> [Integer] có nghĩa là bạn sẽ nhận được một danh sách các số nguyên và trả về một danh sách các số nguyên.

Đến thời điểm này, bạn có thể soạn (.) Một hàm có cùng chữ ký. Nếu bạn kiểm tra loại filter even bạn sẽ thấy rằng đó là: [Integer] -> [Integer], như một ứng cử viên hợp lệ cho sáng tác ở đây.

thành phần này rồi, không làm thay đổi chữ ký cuối cùng của chức năng, nếu bạn kiểm tra các loại: map (*2) . filter even nó là [Integer] -> [Integer]

này sẽ không phải là trường hợp của map (*2) . zipWith max [1,2] [4,5]zipWith max không có cùng chữ ký là chữ ký được mong đợi bởi map (*2).

+0

cảm ơn. Điều này thật ý nghĩa ngay lúc này – wajeeh

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