【发布时间】:2019-01-14 05:04:28
【问题描述】:
我正在为表达式定义一个 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 over a2,但是如果我想fmap over 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 实践中是如何解决这个问题的?
【问题讨论】:
-
仅供参考:在相当新的 GHC 版本中,
DeriveTraversable意味着DeriveFunctor和DeriveFoldable。 -
Csongor Kiss 做了一些非常聪明的工作,用泛型做你想做的事情。我相信其他人也做过相关的事情。这些都不太适合当前的 GHC 仿制药系统。我想该系统将在未来几年内被替换。您可能可以使用 Template Haskell 找到其他解决方案。