Haskell 从应用角度实现幺半群

Haskell 从应用角度实现幺半群,haskell,Haskell,介绍以下练习: 根据单位和(**)实现纯and(),反之亦然 这里是单项式和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 =

介绍以下练习:

根据单位和(**)实现纯and(),反之亦然

这里是
单项式
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 `(<**>)`
instance Monoidal Option where
  u                        = p ()
  dotdot None _            = None 
  dotdot _ None            = None
  dotdot (Some x) (Some y) = Some id <*> Some (x, y)
然后,我定义了
实例MyApplicationOption

instance MyApplicative Option where
  p                = Some
  apply None _     = None
  apply _ None     = None
  apply (Some g) f = fmap g f 
最后,我尝试在
MyApplicative
p
apply
方面实现
Monoidal选项

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 `(<**>)`
instance Monoidal Option where
  u                        = p ()
  dotdot None _            = None 
  dotdot _ None            = None
  dotdot (Some x) (Some y) = Some id <*> Some (x, y)

特别是,我很好奇如何用Applicative的
)正确地实现
dotdot::fa->fb->f(a,b)
——在我的例子中,它是
apply

Applicative
单体
的一种简洁的替代表示形式。这两个类型类是等效的,您可以在这两个类型之间进行转换,而无需考虑特定的数据类型,如
选项
Applicative
的“简洁的备选演示文稿”基于以下两种等效形式

pure a = fmap (const a) unit
unit = pure ()

ff <*> fa = fmap (\(f,a) -> f a) $ ff ** fa
fa ** fb = pure (,) <*> fa <*> fb
替换为
,我们可以将类型
()
和构造函数
():()
替换为以恢复
单元

pure :: a  -> f a
pure    () :: f ()
同样地(虽然不是那么简单)将类型
(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)
Applicative
然后通过将函数application
($)::(a->b)->a->b
提升到函子中来获取nice
操作符

(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 ($)

在下面答案的开头,我们很快解释了其中的大部分内容,解释得很好,谢谢。要不要在这里寄信用卡?
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 ($)
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b