2014-10-31 30 views
8

假设我有一个适用的数据类型A。 (为了举例,我们可以假设AIdentity)。适用于从同一个域到应用的功能的实例

我现在已经从一个A到另一个对应于“转型”新的数据类型:

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

我要定义的琐碎应用型实例(B a)产生这既适用参数的新变革的<*>其输入,然后使用的< *>从A的应用型实例

制定,这是很简单的定义:

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 

但是,我有这样的感觉,应该有一个简单的点写法,使用这个事实(-> a)是一个应用Functor。

由于我有什么想法,我考虑相应的函子实例的定义样本:

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

是否有类似简单的方式来定义应用型实例?

回答

12

关于Applicative的一个整洁的事实是,这个类是在组合下关闭。你可以从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 

Applicative实例(->) a,你带来了,是这样的:

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

现在,让我们扩大Compose ff <*> Compose fa :: Compose ((->) (A a)) A b(一些步骤跳过):

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

所以你在做什么有效的组成(->) (A a)A

+1

说这个问题中的'B a b'是否等于'type B a = Compose(( - >)(A a))A'是否正确? – 2014-10-31 23:04:32

+0

@ChristianConkle:是的。 – 2014-10-31 23:43:55

7

这可能吗?

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

回到Luis Casillas的回答:如果B是字面上的数据类型,您可以简单地使用Compose ((->) (A a)) A。数据构造函数的类型为Compose :: (A a -> A b) -> Compose ((->) (A a)) A b

您还可以使用一个类型的同义词:type B a = Compose ((->) (A a)) A

您可以与ComposeProductSum和朋友一起玩很多有趣的smooshing仿函数。

相关问题