假设我有一个数据类型 A
这是适用的。 (为了这个例子,我们可以假设 A
是 Identity
)。
我现在有一个新的数据类型,它对应于一个 A
的“转换”。给另一个:
data B a b = B (A a -> A b)
我想为
(B a)
定义平凡的 Applicative 实例这会产生一个新的转换,它应用 <*>
的两个参数到它的输入,然后使用 A 的 Applicative 实例中的 <*> 定义。制定这个很简单:
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
是否有类似的简单方法来定义 Applicative 实例?
最佳答案
关于 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
.
关于haskell - 来自同一域的函数的应用实例到 Applicative,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26683564/