- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用syntactic制作 AST 的库。要将 AST 计算为 (Haskell) 值,我的所有节点都需要是语法类 EvalEnv
的实例:
class EvalEnv sym env where
compileSym :: proxy env -> sym sig -> DenotationM (Reader env) sig
语法还提供了“默认”实现:
compileSymDefault :: (Eval sym, Signature sig)
=> proxy env -> sym sig -> DenotationM (Reader env) sig
但是在 EvalEnv
的实例中无法访问 sig
的约束,使得以下(例如,重叠)实例不可能:
instance EvalEnv sym env where
compileSym = compileSymDefault
我的所有用户定义的 AST 节点都是 GADT,通常具有多个构造函数,其中 a
参数始终满足 compileSymDefault
的约束:
data ADDITIVE a where
Add :: (Num a) => ADDITIVE (a :-> a :-> Full a)
Sub :: (Num a) => ADDITIVE (a :-> a :-> Full a)
结果,我发现 所有 EvalEnv
实例如下所示:
instance EvalEnv ADDITIVE env where
compileSym p Add = compileSymDefault p Add
compileSym p Sub = compileSymDefault p Sub
此样板实例对于所有 AST 节点都是相同的,并且每个 GADT 构造函数都需要单独列出,因为 GADT 构造函数签名暗示了 compileSymDefault
约束。
有什么方法可以避免列出我创建的每个节点类型的每个构造函数?
最佳答案
如果我正确理解了这个问题,那么样板文件是由于需要对每个构造函数使用模式匹配来将所需的上下文引入范围内而产生的。除了构造函数名称之外,所有 case 分支都是相同的。
下面的代码使用了 removeBoilerplate
等级 2 函数,可用于将上下文纳入范围内。首先使用样板代码定义两个示例函数,然后转换为使用帮助器 removeBoilerplate
函数。
如果您有多个 GADT,则需要为每个 GADT 定制一个 removeBoilerplate
。因此,如果您需要为每种类型多次删除样板文件,则此方法非常有用。
我不熟悉语法,无法 100% 确定这会起作用,但看起来它有很好的机会。您可能需要稍微调整 removeBoilerplate
函数的类型。
{-# LANGUAGE GADTs , ExplicitForAll , ScopedTypeVariables ,
FlexibleContexts , RankNTypes #-}
class Class a where
-- Random function requiring the class
requiresClass1 :: Class a => a -> String
requiresClass1 _ = "One!"
-- Another one
requiresClass2 :: Class a => a -> String
requiresClass2 _ = "Two!"
-- Our GADT, in which each constructor puts Class in scope
data GADT a where
Cons1 :: Class (GADT a) => GADT a
Cons2 :: Class (GADT a) => GADT a
Cons3 :: Class (GADT a) => GADT a
-- Boring boilerplate
boilerplateExample1 :: GADT a -> String
boilerplateExample1 x@Cons1 = requiresClass1 x
boilerplateExample1 x@Cons2 = requiresClass1 x
boilerplateExample1 x@Cons3 = requiresClass1 x
-- More boilerplate
boilerplateExample2 :: GADT a -> String
boilerplateExample2 x@Cons1 = requiresClass2 x
boilerplateExample2 x@Cons2 = requiresClass2 x
boilerplateExample2 x@Cons3 = requiresClass2 x
-- Scrapping Boilerplate: let's list the constructors only here, once for all
removeBoilerplate :: GADT a -> (forall b. Class b => b -> c) -> c
removeBoilerplate x@Cons1 f = f x
removeBoilerplate x@Cons2 f = f x
removeBoilerplate x@Cons3 f = f x
-- No more boilerplate!
niceBoilerplateExample1 :: GADT a -> String
niceBoilerplateExample1 x = removeBoilerplate x requiresClass1
niceBoilerplateExample2 :: GADT a -> String
niceBoilerplateExample2 x = removeBoilerplate x requiresClass2
关于haskell - 如何废弃我的样板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26109981/
我使用cocos2d-x和Lua进行开发。最近我使用 Instruments 并发现了一些被废弃的内存:cocos2d-x 在自己的自动释放池中对对象执行释放,但我仍然有来自 Lua 的引用。如何确定
我是一名优秀的程序员,十分优秀!