Typeclassopedia提供以下练习:
按单位和(**)实现纯和(<*>),反之亦然.
这是Monoidal和MyApplicative:
class Functor f => Monoidal f where
u :: f () -- using `u` rather than `unit`
dotdot :: f a -> f b -> f (a,b) -- using instead of `(**)`
class Functor f => MyApplicative f where
p :: a -> f a -- using instead of `pure`
apply :: f (a -> b) -> f a -> f b -- using instead of `(<**>)`
Run Code Online (Sandbox Code Playgroud)
首先,让我展示Maybe类似的数据类型:
data Option a = Some a
| None deriving Show
Run Code Online (Sandbox Code Playgroud)
然后,我定义了instance MyApplicative Option:
instance MyApplicative Option where
p = Some
apply None _ = None
apply _ None = None
apply (Some g) f = fmap g f
Run Code Online (Sandbox Code Playgroud)
最后,我尝试在执行Monoidal Option中的条款p及apply的MyApplicative:
instance Monoidal Option where
u = p ()
dotdot None _ = None
dotdot _ None = None
dotdot (Some x) (Some y) = Some id <*> Some (x, y)
Run Code Online (Sandbox Code Playgroud)
这是正确的吗?我的实现dotdot与apply似乎并不
instance Monoidal Option where
u = p ()
dotdot None _ = None
dotdot _ None = None
dotdot (Some x) (Some y) = apply (Some id) (Some (x, y))
Run Code Online (Sandbox Code Playgroud)
特别是,我很好奇如何正确地dotdot :: f a -> f b -> f (a, b)使用Applicative 实现(<*>)- 在我看来是这样的apply.
Cir*_*dec 10
Applicative是一个很好的替代演示文稿Monoidal.两个类型类都是等价的,你可以在不考虑特定数据类型的情况下在两者之间进行转换Option."整齐的替代演示" Applicative基于以下两个等价物
pure a = fmap (const a) unit
unit = pure ()
ff <*> fa = fmap (\(f,a) -> f a) $ ff ** fa
fa ** fb = pure (,) <*> fa <*> fb
Run Code Online (Sandbox Code Playgroud)
获得这个"整洁的替代演示" Applicative的技巧与诀窍相同zipWith- 在接口中替换显式类型和构造函数,以及可以传递类型或构造函数以恢复原始接口的内容.
unit :: f ()
Run Code Online (Sandbox Code Playgroud)
替换为pure我们可以替换类型()和构造函数() :: ()进行恢复unit.
pure :: a -> f a
pure () :: f ()
Run Code Online (Sandbox Code Playgroud)
并且类似地(尽管不是那么简单)用于取代类型(a,b)和构造(,) :: a -> b -> (a,b)成liftA2以回收**.
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 (,) :: f a -> f b -> f (a,b)
Run Code Online (Sandbox Code Playgroud)
Applicative然后<*>通过将函数应用程序提升($) :: (a -> b) -> a -> b到仿函数中来获得好的运算符.
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 ($)
Run Code Online (Sandbox Code Playgroud)
从<*>后面回来liftA2很常见,liftA2包含在内Control.Applicative.的<$>是中缀fmap.
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
Run Code Online (Sandbox Code Playgroud)