Typeclassopedia 提供了以下练习:



这是 MonoidalMyApplicative :

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 `(<**>)`

首先,让我展示类似 Maybe 的数据类型:
data Option a = Some a
                | None deriving Show

然后,我定义了 instance MyApplicative Option :
instance MyApplicative Option where
  p                = Some
  apply None _     = None
  apply _ None     = None
  apply (Some g) f = fmap g f

最后,我尝试根据 Monoidal Optionpapply 来实现 MyApplicative :
instance Monoidal Option where
  u                        = p ()
  dotdot None _            = None
  dotdot _ None            = None
  dotdot (Some x) (Some y) = Some id <*> Some (x, y)

这是正确的吗?我用 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))

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

最佳答案

ApplicativeMonoidal 的一个简洁的替代表示。两个类型类是等效的,您可以在两者之间进行转换,而无需考虑特定的数据类型,例如 OptionApplicative 的“整洁的替代表示”基于以下两个等效项

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

ff <*> fa = fmap (\(f,a) -> f a) $ ff ** fa
fa ** fb = pure (,) <*> fa <*> fb

获得 Applicative 的这种“简洁的替代表示”的技巧与 zipWith 的技巧相同 - 将接口(interface)中的显式类型和构造函数替换为可以传递类型或构造函数以恢复原始接口(interface)的内容。
unit :: f ()

替换为 pure ,我们可以将类型 () 和构造函数 () :: () 替换为 unit 以恢复 (a,b)
pure :: a  -> f a
pure    () :: f ()

同样(虽然不那么简单)将类型 (,) :: a -> b -> (a,b) 和构造函数 liftA2 代入 ** 以恢复 Applicative
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2    (,)           :: f a -> f b -> f (a,b)
<*> 然后通过将函数应用 ($) :: (a -> b) -> a -> b 提升到仿函数中来获得漂亮的 <*> 运算符。
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 ($)

liftA2 返回到 liftA2 很常见,以至于 Control.Applicative is included in <$> fmap 是中缀 ojit_code 。
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b

关于haskell - 在 Applicative 方面实现 Monoidal,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27262232/

10-11 02:35