2010-09-22 35 views
6

Hãy xem nhanh các phiên tương tác sau đây trong GHCi:

 
Prelude> import Control.Applicative 
Prelude Control.Applicative> (+1) <$> [1,2] 
[2,3] 
Prelude Control.Applicative> (+1) <$> (1,2) 
(1,3) 

Tôi đoán có một lý do chính đáng cho hành vi của <$> cặp về, nhưng tôi đã không thể tìm thấy một cho đến nay, vì vậy:

lý do tại sao <$> (hoặc `fmap`) được xác định chỉ hoạt động trên thành viên thứ hai của một cặp chứ không phải trên cả hai giá trị?

+0

Câu hỏi này có liên quan: http://stackoverflow.com/questions/3155469/help-haskell-functors-sink-in/3164774#3164774 –

Trả lời

15

<$> (aka fmap) là một thành viên của lớp functor như vậy:

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Vì vậy, bất cứ điều gì f là phải là một loại parameterised với một đối số kiểu. Danh sách là một loại như vậy, khi được viết ở dạng tiền tố [] ([] a giống như [a]). Vì vậy, các ví dụ cho các danh sách là:

instance Functor [] where 
    -- fmap :: (a -> b) -> [] a -> [] b 
    fmap = map 

cặp cũng có thể được viết dưới dạng tiền tố: (,) a b cũng giống như (a, b). Vì vậy, chúng ta hãy xem xét những gì chúng ta làm nếu chúng ta muốn một cá thể Functor liên quan đến các cặp. Chúng tôi không thể khai báo số instance Functor (,) vì hàm tạo cặp (,) có hai loại - và chúng có thể là các loại khác nhau! Những gì chúng ta có thể làm là khai báo một ví dụ cho (,) a - đó là một loại mà chỉ cần thêm một loại:

instance Functor ((,) a) where 
    -- fmap :: (b -> c) -> (,) a b -> (,) a c 
    fmap f (x, y) = (x, f y) 

Hy vọng rằng bạn có thể thấy rằng định nghĩa của fmap là một hợp lý duy nhất chúng tôi có thể cung cấp. Câu trả lời là tại sao thể hiện functor hoạt động trên mục thứ hai trong một cặp là kiểu cho mục thứ hai xuất hiện cuối cùng trong danh sách! Chúng ta không thể dễ dàng khai báo một cá thể functor hoạt động trên mục đầu tiên trong một cặp. Ngẫu nhiên, điều này nói chung với các bộ dữ liệu lớn hơn, ví dụ: các bốn (,,,) a b c d (aka (a, b, c, d)) cũng có thể có một trường hợp Functor vào mục cuối cùng:

instance Functor ((,,,) a b c) where 
    -- fmap :: (d -> e) -> (,,,) a b c d -> (,,,) a b c e 
    fmap f (p, q, r, s) = (p, q, r, f s) 

Hy vọng rằng sẽ giúp giải thích tất cả!

+0

Bạn đã nhập nhanh hơn sau đó ... argh – fuz

+0

lỗi: ví dụ nên nói 'instance Functor []' thay vì 'lớp'. – hzap

+0

Cảm ơn - hiện đã được khắc phục –

2

Tôi đoán, một bộ không cần phải đồng nhất, tôi có nghĩa là cả hai loại có thể khác nhau. Nếu bạn muốn một tuple đồng nhất, bạn có thể sử dụng một danh sách và sau đó fmap sẽ hoạt động.

Bạn mong đợi như thế nào (+1) ("Hello", 2) để hoạt động?

Prelude> import Control.Applicative 
Prelude Control.Applicative> (+1) <$> ("hello",2) 
("hello",3) 

Chỉ hoạt động, nhưng không có hành vi đặc biệt khi cả hai loại đều giống nhau. Bằng cách này tôi không biết tại sao giá trị thứ hai không được sử dụng thay vì giá trị thứ hai, nhưng dù sao bạn chỉ có thể sử dụng một giá trị.

3

xem xét định nghĩa của Functor typeclass:

class Functor f where 
    fmap :: (a -> b) -> f a -> f b 

Rõ ràng, e có loại * -> *. Vì vậy, bạn chỉ có thể khai báo các cá thể cho một kiểu dữ liệu, có loại * -> *.Những gì bạn có thể làm, đang thực hiện một số nội dung như sau:

instance Functor (,) where 
    fmap :: (a -> b) -> (,) a -> (,) b 

Điều này sẽ hoạt động trên các bộ phận được áp dụng một phần và thực sự không vui. Vì vậy, một định nghĩa các trường hợp như thế này:

instance Functor ((,) a) where 
    fmap :: (b -> c) -> (,) a b -> (,) a c 
    fmap f (x,y) = (x,f y) 

Tóm lại: Không thể ở đồng bằng Haskell 98 (mặc dù tôi tin rằng THT có một phần mở rộng cú pháp cho việc này) để xác định một trường hợp như

gì bạn có thể làm, đang xác định bộ đồ của riêng bạn:

data T a = T a a 

instance Functor T where 
    fmap f (T a b) = T (f a) (f b) 

Sau đó, bạn có thể làm bất cứ điều gì bạn thích. Bạn thấy, bởi vì loại là * -> * thay vì * -> * -> *, mọi thứ đều ổn.

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