我的目标是在DSL中编写名称/值对列表并使其可读.此处的值可以是int,float,string或任何这些类型的列表.
我正在使用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]
Run Code Online (Sandbox Code Playgroud)
编程101:如果你发现自己一遍又一遍地重复同样的事情,将其打包以便重复使用,使其成为一种功能.在您的情况下,该函数将是通用的(即获取任何类型的参数)并对参数执行upcast:
let pair name value = name, value :> obj
myfun [pair "Name" "Freddie"; pair "Age" 50]
Run Code Online (Sandbox Code Playgroud)
嗯......没那么好,是吗?但是等等,我们还没有完成!现在你已经拥有了这个功能,你可以给它一个更好的名字,这会让它变得更好.说,==>:
let (==>) name value = name, value :> obj
myfun ["Name" ==> "Freddie"; "Age" ==> 50]
Run Code Online (Sandbox Code Playgroud)
如果你的可能类型集合是事先知道的并且相对较小(正如你的问题似乎表明的那样),你可以更进一步让编译器检查是否只使用了允许的类型.为此,您需要使用方法重载,静态解析的类型约束和一些语法技巧:
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
Run Code Online (Sandbox Code Playgroud)