如何为这个非平凡的表达式类型定义MuRef实例?

时间:2014-05-23 09:38:48

标签: haskell data-reify

考虑玩具嵌入式语言:

data Expr =
    App Expr Expr 
  | Lam Pat Expr
  | Case Expr [(Pat, Expr)]

我希望使用data-reify观察Expr表达式中的任何隐式共享。为此,我需要一个与图形节点对应的代理类型:

data ExprF e =
    AppF e e
  | LamF Pat e
  | Case e [(Pat, e)]

MuRef类的实例。我可以轻松地为mapDeRefApp构造函数提供Lam的定义,但我不确定如何处理与Case对应的定义:< / p>

instance MuRef Expr where
  type DeRef Expr = ExprF
  mapDeRef f (App e0 e1)  = AppF <$> f e0 <*> f e1
  mapDeRef f (Lam p e)    = LamF p <$> f e
  mapDeRef f (Case e pes) = Case <$> f e <*> ?

根据对this question的回答判断,通过向ExprF添加一些聪明的构造函数以及类似MuRef的实例,看起来可能会发生这种情况。 {1}}和(Pat, Expr)。我试过了:

[(Pat, Expr)]

但是对于data ExprF e = AppF e e | LamF Pat e | Pair (Pat, e) | CaseF e [(Pat, e)] | Cons e e | Nil instance MuRef (Pat, Expr) where type DeRef (Pat, Expr) = ExprF mapDeRef f (p, e) = Pair <$> ((,) <$> pure p <*> f e) instance MuRef [(Pat, Expr)] where type DeRef [(Pat, Expr)] = ExprF mapDeRef _ [] = pure Nil mapDeRef f (pe:pes) = Cons <$> f pe <*> f pes 的原始mapDeRef绑定,没有运气:

Case

是否可以为instance MuRef Expr where ... mapDeRef f (Case e pes) = Case <$> f e <*> f pes Could not deduce (u ~ [(Pat, u)]) from the context (Applicative f) bound by the type signature for mapDeRef :: Applicative f => (forall b. (MuRef b, DeRef Expr ~ DeRef b) => b -> f u) -> Expr -> f (DeRef Expr u) 模式正确定义mapDeRef?有什么简单的我可以忽略吗?

1 个答案:

答案 0 :(得分:3)

可以为原始类型定义实例:

{-# LANGUAGE TypeFamilies, TupleSections #-}

import qualified Data.Traversable as T
import Data.Reify
import Control.Applicative

data Expr =
    App Expr Expr 
  | Lam Pat Expr
  | Case Expr [(Pat, Expr)]

data ExprF e =
    AppF e e
  | LamF Pat e
  | CaseF e [(Pat, e)]

data Pat -- placeholder

instance MuRef Expr where
    type DeRef Expr = ExprF
    mapDeRef f (App e0 e1)  = AppF <$> f e0 <*> f e1
    mapDeRef f (Lam p e)    = LamF p <$> f e
    mapDeRef f (Case e pes) = CaseF <$> f e <*> T.traverse (\(pat, exp) -> (pat,) <$> f exp) pes

我不熟悉Data.Reify,我只是按照类型填写实例定义,所以我不确定语义是否符合你想要的内容;但实例可以肯定完成。

附注:使用lens,实现变得非常明确:

import Control.Lens
-- code omitted
mapDeRef f (Case e pes) = CaseF <$> f e <*> (traverse . _2) f pes