当构造应用于幻像类型时,此构造会导致代码不那么通用

时间:2015-10-02 21:46:14

标签: generics f#

我正在尝试在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类型

不匹配

我似乎无法找到任何方法来规避这种行为,事实上我无法找到导致此代码不如我预期的那样通用的原因。如果可能的话,我宁愿选择一种不完全放弃幻像类型的解决方案。

我做了一些根本错误的事吗?这可能是编译器错误吗?

1 个答案:

答案 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