避免Functor Instance Boilerplate

eaz*_*001 3 haskell boilerplate functor

我有一些数据类型Verb p定义如下:

data Verb p =   Look          {getPreps :: p}
              | LookExtra     {getPreps :: p}
              | Touch         {getPreps :: p}
              | Smell         {getPreps :: p}
              | HearExtra     {getPreps :: p}
              | Hear          {getPreps :: p}
              | Taste         {getPreps :: p}
              | Pickup        {getPreps :: p}
              | PickupExtra   {getPreps :: p}
              | Move          {getPreps :: p}
              | MoveExtra     {getPreps :: p}
              deriving (Show,Ord,Eq)
Run Code Online (Sandbox Code Playgroud)

我必须使这个数据类型成为Functor至少一个实例.因此:

instance Functor Verb where
  fmap f (Look a)        = Look (f a)
  fmap f (LookExtra a)   = LookExtra (f a)
  fmap f (Touch a)       = Touch (f a)
  fmap f (Smell a)       = Smell (f a)
  fmap f (HearExtra a)   = HearExtra (f a)
  fmap f (Hear a)        = Hear (f a)
  fmap f (Taste a)       = Taste (f a)
  fmap f (Pickup a)      = Pickup (f a)
  fmap f (PickupExtra a) = PickupExtra (f a)
  fmap f (Move a)        = Move (f a)
  fmap f (MoveExtra a)   = MoveExtra (f a)
Run Code Online (Sandbox Code Playgroud)

如果那不是样板,那么我不知道是什么.我可以想象,如果我不得不前进Applicative Functors等等,这将成为一种真正的痛苦.有没有更好的方法来写这个而不改变Verb p完全的结构?由于我编写的方式Verb p,似乎我注定要为每个数据类型构造函数声明一个实例.希望我被证明是错的.

lef*_*out 12

看看DeriveFunctor扩展名.正如名称提示,它允许您简单地添加Functorderiving列表中.不幸的是,这并没有扩展到Applicative并且Monad因为,与Functor那些通常没有一种方法来定义实例,而是多种非等效的可能性.

在您的示例中,我将简化数据定义:

data VerbType = Look | LookExtra | ...
type Verb a = (VerbType, a)
-- or data Verb a = Verb { verbType :: VerbType, getPreps :: a }
Run Code Online (Sandbox Code Playgroud)

  • `DerivingFunctor`非常有用,但是对于这种情况,如果你按照建议定义数据类型,你已经有了一个仿函数实例(即`((,)a)`). (2认同)