Как получить несколько экземпляров Functor в Haskell? - PullRequest
0 голосов
/ 14 января 2019

Я определяю 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 и т. д.

Есть ли решение этой проблемы? как люди решают эту проблему в практике хаскелла?

1 Ответ

0 голосов
/ 14 января 2019

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

...