对于一个小的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 42
和Real 13.
)的计算,但能够返回相应的包装器。如果我想添加Real 1.
和Real 1.5
,我想要提取1.0 + 1.5 = 2.5
,然后继续使用Real 2.5
,但我不想将所有内容都作为浮点数处理,以便我拥有整数和浮点数之间的区别。
答案 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