2014-10-31 13 views
8

Giả sử tôi có kiểu dữ liệu A là ứng dụng. (Vì lợi ích của ví dụ, chúng ta có thể giả định AIdentity).Ví dụ ứng dụng cho các chức năng từ cùng một tên miền đến số

bây giờ tôi có một kiểu dữ liệu mới tương ứng với "chuyển đổi" từ một A khác:

data B a b = B (A a -> A b) 

Tôi muốn xác định các trường hợp applicative tầm thường cho (B a) đó tạo ra một sự biến đổi mới mà áp dụng cho cả đối số của <*> đến đầu vào của nó và sau đó sử dụng định nghĩa của < *> từ dụ applicative của A.

Xây dựng này là đủ đơn giản:

instance Applicative (B a) where 
    pure x = B $ const $ pure x 

    (B ftrans) <*> (B xtrans) = B fxtrans 
     where fxtrans inp = let fout = ftrans inp 
           xout = xtrans inp 
          in fout <*> xout 

Tuy nhiên, tôi có cảm giác rằng phải có một cách đơn giản không cần thiết để viết điều này bằng cách sử dụng thực tế là (-> a) là một hàm Functor.

Là một mẫu của những gì tôi có trong tâm trí, hãy xem xét định nghĩa của tôi về trường hợp functor tương ứng:

instance Functor (B a) where 
    fmap f (B xtrans) = B $ (fmap f) <$> xtrans 

Có một cách đơn giản tương tự để xác định các trường hợp applicative?

Trả lời

12

Một trong những sự kiện gọn gàng về Applicative là lớp học này sẽ bị đóng theo sáng tác. Bạn có thể nhận được như sau từ Data.Functor.Compose:

newtype Compose f g a = Compose { getCompose :: f (g a) } 

instance (Functor f, Functor g) => Functor (Compose f g) where 
    fmap f (Compose fga) = Compose (fmap (fmap f) fga) 

instance (Applicative f, Applicative g) => Applicative (Compose f g) where 
    pure a = Compose (pure (pure a)) 
    Compose f <*> Compose x = Compose $ (<*>) <$> f <*> x 

Các Applicative dụ cho (->) a, mà bạn đưa lên, là thế này:

instance Applicative ((->) r) where 
    pure = const 
    ff <*> fa = \r -> let f = ff r 
          a = fa r 
         in f a 

Bây giờ, chúng ta hãy mở rộng Compose ff <*> Compose fa :: Compose ((->) (A a)) A b (một số bước bỏ qua):

Compose ff <*> Compose fa 
    == Compose $ (<*>) <$> ff <*> fa 
    == Compose $ \r -> let f = ff r 
          a = fa r 
         in f <*> a 

Vì vậy, những gì bạn đang thực hiện có hiệu quả là thành phần của (->) (A a)A .

+1

Sẽ đúng khi nói rằng 'B a b' trong câu hỏi tương đương với' loại B a = Soạn ((->) (A a)) A'? –

+0

@ChristianConkle: Có. –

7

Điều này, có thể?

(B ftrans) <*> (B xtrans) = B ((<*>) <$> ftrans <*> xtrans) 
2

Để đáp lại câu trả lời của Luis Casillas: Nếu B là kiểu dữ liệu bạn đang làm việc, bạn có thể chỉ cần sử dụng Compose ((->) (A a)) A thay thế. Trình tạo dữ liệu sẽ có loại Compose :: (A a -> A b) -> Compose ((->) (A a)) A b.

Bạn cũng có thể sử dụng loại từ đồng nghĩa: type B a = Compose ((->) (A a)) A.

Bạn có thể có nhiều footors vui vẻ cùng với Compose, Product, Sum và bạn bè.

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