Как получить несколько экземпляров 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 Есть, но я подозреваю, что вы действительно хотите это сделать. Выравнивание единообразия в ваших типах данных может значительно очистить остальную часть вашего кода: оно может выявить скрытые возможности для обобщения, выявить стандартные структуры, на которые вы полагаетесь, и уменьшить количество стандартных функций, опираясь больше на стандартную библиотеку.

Другие вопросы по тегам