“Unbox”多功能类型的歧视联盟/搜索良好的解决方法

时间:2011-10-30 16:13:53

标签: types f# type-inference abstract-syntax-tree discriminated-union

对于一个小的AST解析器,我有一个小的区别联盟

type Numerical =
    | Int of int
    | Real of float

用于其他一些结构,如

type Vector = Numerical list
Vector [Int 42; Real 13.5]

当我有这样的方法时

let eval (e:Numerical) =
    match e with
    | Int n -> ... (* return int *)
    | Real r -> ... (* return float *)

我知道F#推断int类型并在第二行产生Real模式的错误,所以我想知道哪个代码设计是最好的一个处理这种“通用”类型并返回给定类型的适当值。

修改

我在这里有情况导致像

这样的功能
let getInt = function
| Int n -> n
| Real _ -> failwith "Given value doesn't represent an int"

let getReal = function
| Real n -> n
| Int _ -> failwith "Given value doesn't represent a real number"

但是我想要一种方法来封装两种情况并“自动选择正确的”。

这一整个工作应该能够真正运行带有原始数据类型的“盒装”值(如Int 42Real 13.)的计算,但能够返回相应的包装器。如果我想添加Real 1.Real 1.5,我想要提取1.0 + 1.5 = 2.5,然后继续使用Real 2.5,但我不想将所有内容都作为浮点数处理,以便我拥有整数和浮点数之间的区别。

2 个答案:

答案 0 :(得分:3)

您可以将结果投射到obj

let eval (e:Numerical) =
    match e with
    | Int n -> n :> obj
    | Real r -> r :> obj

但那可能不是你想要的。

另一种选择是在Numerical上实施您自己的操作:

let (+) a b =
    match (a,b) with
    | (Int an, Int bn) -> Int (an + bn)
    | (Real ar, Real br) -> Real (ar + br)
    | _ -> failwith "Can't add Int and Real"

根据某个运行时值,您不能拥有具有不同编译时返回类型的函数。

答案 1 :(得分:0)

let eval<'T> (e:Numerical):'T =
    match e with
    | Int n -> n :> obj :?> 'T
    | Real r -> r :> obj :?> 'T

<强>样本

> eval<float>(Real 4.5);;
val it : float = 4.5
> eval<int>(Int 42);;
val it : int = 42
> let x:float = eval (Real 5.5);;
val x : float = 5.5
> let x:int = eval (Real 5.5);;//NG typemismatch