最近我介绍了功能依赖和类型系列。对于一个类项目,我为Java和Haskell中的C子集编写(完成)了一个解释器。用于术语的评估函数的Haskell实现需要使用显式模式匹配和展开表示文字的值构造函数来构建“函数表”。一种不愉快的情况(但比Java更漂亮)。
在搜索了一段时间后,我遇到了“集合”示例,想知道我是否可以将其应用于我的抽象语法,以便为文字生成通用的“注入”和“项目自”函数。我想出了两个初步的测试尝试:
(使用函数依赖:注入和投影函数在没有显式类型注释的情况下工作, Lit 注入 lit 也是如此。但是,的投影函数点亮不会输入,错误“无法将预期类型l
与推断类型l'
匹配”。)
class Prim l a | l -> a, a -> l where
inj :: a -> l
proj :: l -> a
instance Prim LB Bool where inj = LB; proj = lb
instance Prim LI Int where inj = LI; proj = li
data LB = LB {lb :: Bool}
data LI = LI {li :: Int}
data E where Lit :: Prim l a => l -> E
lit :: Prim l a => l -> E
lit = Lit
unlit :: Prim l a => E -> l
unlit (Lit a) = a
(使用类型系列。这里的问题是我不能让Haskell从参数推断没有显式注释的正确返回类型,而且我不能编写泛型函数lit :: Val l -> E
和{{1 }}。)
unlit :: E -> Val l
我不太了解类型系列,并且对功能依赖性有一个脆弱的把握。但是我想知道两件事:(a)我想要的功能是否可以输入和实现; (b)如果我误解了一些基本的东西。它几乎可以工作,但我现在已经和类型检查器争了一段时间了。
编辑这是我想要的简单模型,因为它不清楚。类class Show l => Prim l where
type Val l :: *
inj :: Val l -> l
proj :: l -> Val l
data LB a = LB {lb :: Bool}
data LI a = LI {li :: Int }
instance Prim (LB a) where type Val (LB a) = Bool; inj = LB; proj = lb
instance Prim (LI a) where type Val (LI a) = Int; inj = LI; proj = li;
data E where
Lit :: Prim l => l -> E
Bin :: Op -> E -> E -> E
基本上实现了我想要的功能。但我无法收集各种“可以包装和不可挽回的”价值,以便制作出一个AST。
Bin
答案 0 :(得分:4)
定义Lit
构造函数的方式将阻止您突出显示它包含的值,无论您如何定义投影函数。
让我们看一下构造函数的类型:
Lit :: Prim l => l -> E
类型变量l
出现在参数中,但不出现在返回类型中。这意味着当你构造一个Lit时,你输入一个属于Prim成员的某种类型的值,然后永久地忘记它的类型。
我不确定你想如何消除模式匹配和值构造函数的展开。对于如何进行预测,您基本上有两种选择:
有理由使用编译时证明,但看起来你没有任何这些原因。
答案 1 :(得分:1)
如果您仍想坚持多态E
的想法。您可以使用多态函数:
withUnlit :: E -> (forall l . Prim l => l -> b) -> b
withUnlit (Lit a) f = f a
但你唯一可以做的事情(你给Prim l
提供的特质)是:
showE :: E -> String
showE e = withUnlit e show
inj
和proj
。但除了使用Val l
之外,您无法使用Data.Dynamic
(如果这是我认为的那样)。