我正在尝试在F#中使用小语言实现DSL。不幸的是,当我试图约束节点以保存其他类型信息时(通过幻像类型),编译器阻止了我的追踪。
以下代码行说明了这个问题:
type Expr<'a> =
| Int of int
| Eq of Expr<int> * Expr<int>
| Not of Expr<bool>
let rec to_string (expr: Expr<'a>) =
match expr with
| Int(n) -> string n
| Eq(x, y) -> sprintf "%s == %s" (to_string x) (to_string y)
| Not(b) -> sprintf "!%s" (to_string b)
根据编译器,构造to_string x
发出以下警告:
构造导致代码不如类型注释所指示的那样通用。类型变量&#39; a已被约束为类型&#39; int&#39;。
然后,在下一行,构造to_string b
发出此错误:
类型不匹配。期待
不匹配Expr<int>
,但Expr<bool>
int
类型与bool
类型
我似乎无法找到任何方法来规避这种行为,事实上我无法找到导致此代码不如我预期的那样通用的原因。如果可能的话,我宁愿选择一种不完全放弃幻像类型的解决方案。
我做了一些根本错误的事吗?这可能是编译器错误吗?
答案 0 :(得分:9)
您需要使to_string
函数具有通用性:
let rec to_string<'a> (expr:Expr<'a>) : string =
match expr with
| Int(n) -> string n
| Eq(x, y) -> sprintf "%s == %s" (to_string x) (to_string y)
| Not(b) -> sprintf "!%s" (to_string b)
调用函数
时将推断出type参数Not (Eq (Int 1, Int 2))
|> to_string