Как получить несколько экземпляров Functor в Haskell?
Я определяю AST для выражения, и у него есть три типа аргументов, например:
{-# language DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
-- | a general represetation of an expression
-- , with ref info contained in r and two attributes contained in a1, a2
data Expr r a1 a2
= Ref r a1 a2
| App FunName [Expr r a1 a2] a1 a2
| Lit Value a1 a2
deriving (Functor, Foldable, Traversable)
Сейчас использую DeriveFunctor
может только помочь мне определить instance Functor (Expr r a1)
, Так что я могу fmap
над a2
, но если я хочу fmap
над a1
или же r
Я считаю, что это невозможно использовать DeriveFunctor
с newtype
, поскольку следующий код не работает:
newtype ExprR a1 a2 r = MkExprR { getExpr :: Expr r a1 a2 }
deriving instance Functor (ExprR a1 a2)
Если мне нужны только два аргумента типа, то Bifunctor
может быть хорошей идеей, и действительно есть какой-то пакет, который обеспечивает DeriveBifunctor
, но что, если нам нужно три? нам нужно DeriveTrifunctor
или же DeriveQuadfunctor
так далее.?
И что, если нам нужно больше, чем Functor
? принимая во внимание Foldable
, Traversable
и т.п.
Есть ли решение этой проблемы? как люди решают эту проблему на практике в Haskell?
1 ответ
Не прямой ответ на ваш вопрос, а наблюдение. Если это реальный тип, с которым вы работаете, он может использовать некоторую факторизацию. a1
а также a2
используются одинаково, и они используются один раз на узел. Вы можете учесть это.
data ExprNode r a = ExprNode (ExprF r a) a
-- it's a bifunctor
data ExprF r a
= Ref r
| App FunName [ExprNode r a]
| Lit Value
-- it's a bifunctor
type Expr r a1 a2 = ExprNode r (a1, a2)
Теперь все, что вам нужно, это бифунктор. Если вы хотите сделать это, зависит от того, что вы подразумеваете a1
а также a2
Есть, но я подозреваю, что вы действительно хотите это сделать. Выравнивание единообразия в ваших типах данных может значительно очистить остальную часть вашего кода: оно может выявить скрытые возможности для обобщения, выявить стандартные структуры, на которые вы полагаетесь, и уменьшить количество стандартных функций, опираясь больше на стандартную библиотеку.