我正在尝试按照我的建议回答这个stackoverflow问题,uniplate
但到目前为止我提出的唯一解决方案非常难看.
这似乎是一个相当普遍的问题,所以我想知道是否有更优雅的解决方案.
基本上,我们有一个GADT可以解析为Expression Int
或者Expression Bool
(忽略codataIf = If (B True) codataIf codataIf
):
data Expression a where
I :: Int -> Expression Int
B :: Bool -> Expression Bool
Add :: Expression Int -> Expression Int -> Expression Int
Mul :: Expression Int -> Expression Int -> Expression Int
Eq :: Expression Int -> Expression Int -> Expression Bool
And :: Expression Bool -> Expression Bool -> …
Run Code Online (Sandbox Code Playgroud) 我们来看看以下代码:
transformBi (++"asdasd") [1,2,3,4]
Run Code Online (Sandbox Code Playgroud)
显然,这段代码什么都不做,但它仍然编译得很好.我想创建一个新版本的transformBi,如果编译器可以通过类型证明它是无操作,则不会编译.理想情况下,这可以通过调用的类型类来完成Contains
,这样新的类型transformBi
就可以了
transformBi :: (Biplate from to, Contains from to) => (to -> to) -> from -> from
Run Code Online (Sandbox Code Playgroud)
我们如何实施Contains
?
我正在寻找一个Contains
可以自动导出的东西,而不是我必须为每个代数数据类型编写的东西.
AndrásKovács 在回答前一个问题时提出了这个问题.
在镜头风格的uniplate库中,* -> *
基于类的类型
class Uniplate1 f where
uniplate1 :: Applicative m => f a -> (forall b. f b -> m (f b)) -> m (f a)
Run Code Online (Sandbox Code Playgroud)
类似于类的种类 *
class Uniplate on where
uniplate :: Applicative m => on -> (on -> m on) -> m on
Run Code Online (Sandbox Code Playgroud)
是有可能实现类似物contexts
和holes
,二者均具有类型Uniplate on => on -> [(on, on -> on)]
,而不需要Typeable1
?
很明显,这可以在uniplate库的旧式中实现,该库用于Str
通过返回具有子类型的类型级列表的结构来表示数据的结构.
一个洞可以用以下数据类型表示,它将替换(on, on -> on)
为contexts …