2014-01-04 5 views
3

У меня есть несколько типов данных Verb p определены как таковые:Избегайте Functor Instance шаблонный

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) 

Я должен сделать этот тип данных экземпляра 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) 

Если это не шаблон, то я не знаю, что есть. Я могу представить, что это становится настоящей болью, если я должен прогрессировать до Applicative Functors и так далее. Есть ли лучший способ написать это без изменения структуры Verb p? Из-за того, как я написал Verb p, кажется, что я обречен объявлять экземпляр для каждого конструктора типов данных. Надеюсь, я ошибаюсь.

ответ

12

Проверьте расширение DeriveFunctor. Как подсказки названия, вы можете просто добавить Functor в список deriving. К сожалению, это не распространяется на Applicative и Monad, потому что, в отличие от Functor, у них обычно нет один способ определить экземпляр, но несколько неэквивалентных возможностей.

В вашем примере, я бы упростить определение данных:

data VerbType = Look | LookExtra | ... 
type Verb a = (VerbType, a) 
-- or data Verb a = Verb { verbType :: VerbType, getPreps :: a } 
+2

'DerivingFunctor' очень полезно, но в этом случае, у вас уже есть экземпляр функтора (а именно' ((,) а) '), если вы определяете тип данных, как предлагается. – user2407038

+1

Это очень полезное расширение; Я не знал об этом. Тем не менее, я думаю, что ваш второй кусочек совета (сделавший небольшую реструктуризацию моего типа данных), вероятно, в целом полезен для моей ситуации. Большое спасибо. – eazar001