考虑玩具嵌入式语言:
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
类的实例。我可以轻松地为mapDeRef
和App
构造函数提供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
?有什么简单的我可以忽略吗?
答案 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