2010-02-25 30 views
11

tôi đã viết một cái gì đó như thế này:Thao tác thứ tự của đối số để gõ constructors

instance Functor (Either e) where 

    fmap _ (Left a) = Left a 

    fmap f (Right b) = Right (f b) 

Làm thế nào để làm như vậy nếu tôi muốn fmap để thay đổi giá trị duy nhất nếu nó Left?

Ý tôi là, tôi sử dụng cú pháp nào để cho biết rằng tôi sử dụng loại Either _ b thay vì Either a _?

+1

Liên quan: http://stackoverflow.com/questions/1827645 Tóm lại, không thể thực hiện được trong Haskell như hiện tại. – ephemient

+0

Như một sang một bên, tiêu đề của câu hỏi này có phần không rõ ràng, nhưng tôi không chắc điều gì sẽ tốt hơn. –

+0

Tôi đã đề xuất một tiêu đề chính xác hơn. –

Trả lời

7

Tôi không nghĩ rằng có một cách để làm điều đó trực tiếp, thật không may. Với hàm bạn có thể sử dụng flip để áp dụng một phần đối số thứ hai, nhưng điều đó không hoạt động với các hàm tạo kiểu như Either.

Điều đơn giản nhất có lẽ là gói nó trong một newtype:

newtype Mirror b a = Mirrored (Either a b) 

instance Functor (Mirror e) where 
    fmap _ (Mirrored (Right a)) = Mirrored $ Right a 
    fmap f (Mirrored (Left b)) = Mirrored $ Left (f b) 

Wrapping với newtype cũng là cách tiêu chuẩn để tạo ra nhiều trường hợp cho một loại duy nhất, chẳng hạn như SumProduct là trường hợp của Monoid cho số loại. Nếu không, bạn chỉ có thể có một phiên bản cho mỗi loại.

Bên cạnh đó, tùy thuộc vào những gì bạn muốn làm, tùy chọn khác là để bỏ qua Functor và xác định lớp kiểu riêng của bạn như thế này:

class Bifunctor f where 
    bimap :: (a -> c) -> (b -> d) -> f a b -> f c d 

instance Bifunctor Either where 
    bimap f _ (Left a) = Left $ f a 
    bimap _ g (Right b) = Right $ g b 

instance Bifunctor (,) where 
    bimap f g (a, b) = (f a, g b) 

Rõ ràng, lớp đó là gấp đôi so với nhiều niềm vui như một thường xuyên Functor. Tất nhiên, bạn không thể thực hiện một ví dụ Monad trong số đó rất dễ dàng.

+1

Điều gì về 'newtype Flip t a b = Lật (t b a)' và sau đó 'instance Functor (Flip Either e)'? –

+0

Nó không hoạt động: "Tất cả các loại cá thể phải có dạng (T a1 ... an) trong đó a1 ... là kiểu * biến *" – mik01aj

+0

@ m01: Nó hoạt động, nhưng yêu cầu kích hoạt phần mở rộng ngôn ngữ GHC . Trong thực tế, tôi sẽ hoặc là (không có ý định chơi chữ) làm theo cách mà Norman Ramsey đề xuất hoặc sử dụng lớp 'Bifunctor' như trong câu trả lời của tôi. Loại 'Mirror' quá chuyên dụng có ý nghĩa chủ yếu để minh họa cho ý tưởng. –

3

Về cơ bản, bạn cần bộ kết hợp 'lật' trên các loại. Trình bao bọc newtype để đảo ngược thứ tự sẽ hoạt động, như camccann nói. Lưu ý rằng bạn không thể sử dụng từ đồng nghĩa 'loại', vì chúng có thể không được áp dụng một phần.

4

Bạn không thể tạo phiên bản bạn đang tìm kiếm trực tiếp.

Để suy luận kiểu và nhập các lớp để hoạt động, có một thiên vị vị trí nhất định đối với thứ tự các đối số trong các loại. Nó đã được chỉ ra rằng nếu chúng ta cho phép tùy ý sắp xếp lại các đối số khi khởi tạo các lớp kiểu, thì suy luận kiểu đó trở nên khó nhận.

Bạn có thể sử dụng lớp Bifunctor có thể ánh xạ riêng trên cả hai đối số.

class Bifunctor f where 
    bimap :: (a -> b) -> (c -> d) -> f a c -> f b d 
    first :: (a -> b) -> f a c -> f b c 
    second :: (c -> d) -> f a c -> f a d 

    first f = bimap f id 
    second = bimap id 

instance Bifunctor Either where 
    bimap f _ (Left a) = Left (f a) 
    bimap _ g (Right b) = Right (g b) 

instance Bifunctor (,) where 
    bimap f g (a,b) = (f a, g b) 

Hoặc bạn có thể sử dụng một combinator Flip như:

newtype Flip f a b = Flip { unFlip :: f b a } 

phiên bản tổng quát của cả hai trong số này là có sẵn trong thể loại-extras trên hackage. Vị trí thứ hai thậm chí bao gồm một phiên bản cho Functor (Flip Either a)Either là một Bifunctor. (Có lẽ tôi nên sửa lỗi đó để chỉ yêu cầu một số PFunctor)

Cuối cùng, thứ tự của các đối số trong một hàm tạo kiểu là quan trọng trong việc xác định các lớp bạn có thể khởi tạo. Bạn có thể cần phải sử dụng trình bao bọc newtype (như Flip ở trên) để đặt các đối số mà chúng cần phải đủ điều kiện để xây dựng một cá thể của một kiểu chữ khác. Đây là mức giá mà chúng tôi phải trả cho suy luận về các ràng buộc lớp loại.

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