如何在不使用upcast的情况下编写(string * obj)列表

问题描述:

我的目标是在DSL中编写名称/值对列表并使其可读。这里的值可以是int,float,string或任何这些类型的列表。如何在不使用upcast的情况下编写(string * obj)列表

我正在使用string * obj对,并将它们传递给需要(string * obj) list的函数。

是否有写入列表而没有向上注册obj参数?

let myfun (values:(string*obj) list) = 
    // Do something... 

// This is pretty ugly 
myfun ["Name", upcast "Freddie"; "Age", upcast 50] 

// This would be the ideal 
myfun ["Name", "Freddie"; "Age", 50] 

编程101:如果你发现自己一遍又一遍地重复同样的事情,包起来再利用,使之成为功能。在你的情况下,该功能将是通用的(即采取任何类型的参数),并做上溯造型上的参数:

let pair name value = name, value :> obj 
myfun [pair "Name" "Freddie"; pair "Age" 50] 

嗯......不是更漂亮,是吗?但是等等,我们还没有完成!现在你有了这个功能,你可以给它一个更好的名字,这会使它更好。再说了,==>

let (==>) name value = name, value :> obj 
myfun ["Name" ==> "Freddie"; "Age" ==> 50] 

如果可能的类型的一组是预先知道的和相对较小的(如你的问题似乎表明),你可以走了一步,有那些只使用允许的类型编译器检查。要做到这一点,你需要使用方法重载,静态解析类型约束和一些语法挂羊头卖狗肉:

type Casters() = 
    static member cast (v: string) = v :> obj 
    static member cast (v: float) = v :> obj 
    static member cast (v: int) = v :> obj 
    static member cast (v: string list) = v :> obj 
    static member cast (v: float list) = v :> obj 
    static member cast (v: int list) = v :> obj 

let inline cast (casters: ^c) (value: ^t) = 
    ((^c or ^t) : (static member cast : ^t -> obj) value) 

let inline (==>) name value = name, (cast (Casters()) value) 

["Name" ==> "Freddie"; "Age" ==> 50] // OK 
["What?" ==> true] // Error: "bool" is not an allowed type 
+0

谢谢你,但你的_pair_功能给了我_The静态强制从类型”一到“b包括基于在此之前的节目point_信息不确定的类型。你没有看到同样的错误? [tryfsharp](http://www.tryfsharp.org/create/seankearon/file3.fsx) –

+2

一个错误。我复制了你的'upcast',而不是真正的类型为upcast的操作符。现在纠正它。 –

+0

很可爱,谢谢! –

你说你的值只能有一定的上市类型。我想知道你是否有特别的理由使用obj而不是歧视的工会,这完全适合这项工作?

我修改Fyodor的答案使用DU类型,而不是obj

type Value = 
    | Int  of int  | Float  of float  | String  of string 
    | IntList of int list | FloatList of float list | StringList of string list 

type Casters() = 
    static member cast v = Int v 
    static member cast v = Float v 
    static member cast v = String v 
    static member cast v = IntList v 
    static member cast v = FloatList v 
    static member cast v = StringList v 

let inline cast (casters: ^c) (value: ^t) = 
    ((^c or ^t) : (static member cast : ^t -> Value) value) 

let inline (==>) name value = name, (cast (Casters()) value) 

["Name" ==> "Freddie"; "Age" ==> 50] // OK 
["What?" ==> true] // Error: "bool" is not an allowed type 

这种方法的好处是,你现在有类型检查的模式匹配当您访问的值,你不“T要做obj的不安全的向下转换:

let myfun (values:(string*Value) list) = 
    values 
    |> List.map (fun (k, v) -> 
     match v with 
     | Int v -> k + ":" + string v 
     | String v -> k + ":" + v.Trim()) 
     // etc. 
    |> String.concat "\n" 

myfun ["Name" ==> "Freddie"; "Age" ==> 50] |> printfn "%s" 
//Name:Freddie 
//Age:50 
+0

是的,这是一个很好的观点。我在这个程序的其他地方做这个事情,这个问题涉及DSL构成的代码。 –