值得一提的数据结构的一些功能: 这些功能不会都有相同的签名(我的主要问题) 2.数据结构不必是不可变的
我对所有主要的vanilla数据结构感到满意,我关心的是“泛化类型”是表示这类函数集合中的函数的最佳类型。特别是,他们的任何东西都比将它们装箱为obj / System.Object?
更好当函数被“打包”到数据结构中时,我将知道它的签名。这可以以某种方式存储并链接到此函数,以便在需要时可以将函数“解包”为正确的形式。
我假设我可以创建函数签名类型并将它们存储在自己的集合中 - 也许这是一个不好的假设?换句话说:
let f1: float-> float
let f2: string->bool->float
typeof(f1)
和typeof(f2)
是否可以存储在同一数据结构中。我认为既然它们都是Type
类型,这应该是可能的
@ildjarn在回复下面的评论时:预期的签名可能是通常的嫌疑人的任何1-5输入参数组合,例如float,string,bool,date和结果参数在float上的变化。字符串|布尔。
考虑到上述情况,如何最好地存储这些功能,以便以后检索和应用(部分或全部)和/或与其他功能合成。
我能想出的最简单的方法如下:
let f1 x = exp x
let t1 = f1.GetType()
let o1 = box f1 // alternate syntax
let f11 = o1 :?> t1 // ?? FAILS HERE!!!!!
f11 3.0
但是我不知道如何从对象转发回到拳击之前的函数类型。
答案 0 :(得分:2)
为不同的sigs建立一个有区别的联盟(DU):
type Function<'a, 'b, 'c, 'd> =
| Unary of ('a -> 'd)
| Binary of ('a -> 'b -> 'd)
| Ternary of ('a -> 'b -> 'c -> 'd)
然后说出Function<'a, 'b, 'c, 'd> list
来保存你的功能。这应该足够好,只要签名不是太多异类。因为您仍然需要拥有与DU中的案例一样多的不同类型的签名。
完整的示例可能如下所示:
open System
type Operator =
| Parse of (string -> int)
| Unary of (int -> int)
| Binary of (int -> int -> int)
| Print of (int -> unit)
type Data =
| Int of int
| String of string
type StackContent =
| Data of Data
| Operator of Operator
let input = [
Data (String "3")
Operator (Parse Int32.Parse)
Data (String "5")
Operator (Parse Int32.Parse)
Operator (Binary (+))
Operator (Unary (~-))
Operator (Print (printfn "%d"))]
let eval input =
let rec eval = function
| Data d :: inputTail, stack -> eval (inputTail, d::stack)
| Operator (Parse parse) :: inputTail, String s :: stackTail -> eval (inputTail, Int (parse s) :: stackTail)
| Operator (Binary (++)) :: inputTail, Int l :: Int r :: stackTail -> eval (inputTail, Int (l ++ r) :: stackTail)
| Operator (Unary (!)) :: inputTail, Int i :: stackTail -> eval (inputTail, Int !i :: stackTail)
| Operator (Print print) :: inputTail, Int i :: stackTail ->
print i
eval (inputTail, stackTail)
| [], [] -> ()
| input, stack -> failwithf "the following thing is not properly typed\nInput: %A\Stack: %A" input stack
eval (input,[])
eval input
答案 1 :(得分:1)
这取决于您执行此操作的上下文,但您需要以某种方式包装函数和参数。您可以将它们打包并使用obj
值(然后使用反射),您可以将它们包装在有区别的联合中,您可能会做其他事情。
歧视的工会方法可能是最简单的方法。您可以为您支持的不同类型的值设置DU:
type Value =
| Int of int
| String of string
然后一个函数获取一个值列表并生成一个值(你可以选择它,因为如果它得到不正确的参数,函数可能会失败):
type Function = Value list -> Value option
要定义函数集合,可以创建列表。每个函数都会在输入上进行模式匹配,以确保它获得预期的值:
let functions =
[ ( function
| [ Int n; String t ] ->
Some(String(sprintf "The %s is %d" t n))
| _ -> None) ]
然后你可以创建一个参数列表并调用函数:
let arguments = [ Int 42; String "Answer" ]
functions.[0] arguments
这实际上只是众多选项中的一种,但它是最简单的选择之一。缺点是您需要显式解包参数并将结果包装在Value
中 - 但您可能稍后使用某种反射或类型转换来自动化它。