我试图在Haskell中实现以下功能:
0,1,2,...:N
x,y,z,...:V
+,*,-,/,...:F
F alias for Expr -> Expr -> Expr
Expr := N|V|F Expr Expr
我的问题首先是:
语法是否在类型级别存在缺陷?这有意义吗?所有术语看起来都是类型检查(允许0,1,...同时是Expr和N子类型,x,y,...是Expr和V子类型。)
其次,最接近的Haskell实现是什么?我目前的Haskell实现是:
data F = +|-|*|...
data Expr = N|V|MakeExpr F Expr Expr
有什么建议吗?
编辑 -
语法和实现之间的关键区别在于语法中隐式/省略了类型构造函数。为什么Haskell中的类型构造函数是强制的?
答案 0 :(得分:2)
语法和实现之间的关键区别在于语法中隐式/省略了类型构造函数。为什么Haskell中的类型构造函数是强制的?
语法是否在类型级别存在缺陷?是否有意义?所有术语看起来都是类型检查(允许0,1,...同时是Expr和N子类型,x,y,...是Expr和V子类型
数据构造函数 1 在Haskell中是必需的具体,以确保不能具有x,y ,. 。是Expr和V亚型。
因此,您的语法看起来像是您希望语言术语如何工作的合理模型。但是,作为一种直接设计,你想要将你的语言术语表示为Haskell数据类型是没有意义的。
基本上,Haskell故意没有子类型。它确保在您创建新类型(使用newtype
或data
)时,新类型的所有值都与所有其他现有类型的值(以及将创建的所有类型)不同在未来)。它通过使用户定义类型的值总是出现在构造函数中来实现这一点(并且使得#34;重用"构造函数;无论何时创建新类型,都会创建新的)。
Haskell的类型系统的工作方式取决于缺少子类型。您可以设计一种允许子类型的语言(可能参见Scala)。但它从根本上说不是Haskell。
但你可以做的是定义类似的东西:
data Expr
= ExprN N
| ExprV V
| ExprF Expr Expr
您仍然无法获得N
值,只能将其用作Expr
。但您可以将ExprN
应用于它,然后您拥有Expr
。而且,如果Haskell允许您使用n
类N
作为Expr
,那么它真的没有负担,但只需要添加类型注释澄清这就是你的意思;你只需说ExprN n
而不是n :: Expr
。
同样地,如果您有Expr
,并且想要在N
上应用函数,那么case语句将从N
构造函数中提取ExprN
(如果那里的代码真的不再是你必须写的,以检查你的Expr
是否真的是N
。
1 " 输入构造函数"是Haskell中的一个特定术语,这不是我们在这里谈论的内容。我非常确定你的意思是"类型的构造函数"但是要迂腐你通过使用该术语意外地引用了不同的东西。
要清除它,当您声明类似data Maybe a = Nothing | Just a
的类型时,Nothing
和Just
是新的数据构造函数("构造函数&#34 ; on on on极可能意味着数据构造函数)而Maybe
是一个新的类型构造函数。