F# 如何用任意数量的参数约束函数的返回类型?

F# 如何用任意数量的参数约束函数的返回类型?,f#,F#,我想创建一个带有类型注释的记录类型,约束条件是注释必须是返回特定类型的函数。考虑下面的例子: 输入Foo int>={ 函数:'Input->int } 类型ReturnsInt=FSharpFunc={ 函数:'ArgumentTuples->int } {Function=fun a,b,c,d,e,f,g->2}// {Function=fun a->2}//有效 {Function=fun a->}//不起作用 虽然这种方法有其自身的问题,并且不是原始问题的具体答案,但这种变通方法/工作

我想创建一个带有类型注释的记录类型,约束条件是注释必须是返回特定类型的函数。考虑下面的例子:

输入Foo int>={ 函数:'Input->int } 类型ReturnsInt=FSharpFunc={ 函数:'ArgumentTuples->int } {Function=fun a,b,c,d,e,f,g->2}// {Function=fun a->2}//有效 {Function=fun a->}//不起作用
虽然这种方法有其自身的问题,并且不是原始问题的具体答案,但这种变通方法/工作流调整对我来说可能就足够了。我将把这个问题留待讨论。无论如何,我不能把这个评论标记为答案。

这样的东西可能适合你,尽管你应该小心不要失去总体印象。如果数据模型非常复杂,分支可能会爆炸

module FunctionTests

//define function types templates
type F1<'a> = 'a -> int
type F2<'a, 'b> = 'a -> 'b -> int
type F3<'a, 'b, 'c> = 'a -> 'b -> 'c -> int
type F4<'a, 'b, 'c, 'd> = 'a -> 'b -> 'c -> 'd -> int

//define actual functions
let f1 : F1<string> = fun x -> 
                        printf "calling f1: %s\n" x
                        1
let f2 : F2<string, string> = fun x y -> 
                        printf "calling f2: %s; %s\n" x y
                        2
let f3 : F3<string, string, int> = fun x y z -> 
                        printf "calling f2: %s; %s; %d\n" x y z
                        3
let f4 : F4<string, string, int, int> = fun x y z v -> 
                        printf "calling f2: %s; %s; %d; %d\n" x y z v
                        4

//define DU limiting to a subset of functions
type FunctionChooser = 
    | FF1 of F1<string>
    | FF2 of F2<string, string>
    | FF3 of F3<string, string, int>
    | FF4 of F4<string, string, int, int>

//define a record with the DU
type FunctionRec = {Function : FunctionChooser}


//testing harness
let callFunction (functiondefs : FunctionRec) data otherdata intparam1 intparam2 = 
    match functiondefs.Function with
    | FF1 fn -> fn data
    | FF2 fn -> fn data otherdata
    | FF3 fn -> fn data otherdata intparam1
    | FF4 fn -> fn data otherdata intparam1 intparam2


//tests
let res1 = callFunction {Function=FF1 f1} "somedata" "otherdata" 13 14
let res2 = callFunction {Function=FF2 f2} "somedata" "otherdata" 13 14
let res3 = callFunction {Function=FF3 f3} "somedata" "otherdata" 13 14
let res4 = callFunction {Function=FF4 f4} "somedata" "otherdata" 13 14

也许我在这里遗漏了一些东西,但为什么不简单地将您的类型定义为:

type Foo<'InputType> = {
    Function: ('InputType -> int)
}
或更通用:

type Foo<'InputType, 'OutputType> = {
    Function: ('InputType -> 'OutputType)
}
编辑:好的,我看到问题了。 因此,要使用Fyodors溶液,请执行以下操作:

type Foo<'InputType> = {
    Function: ('InputType -> int)
}

let add a b = a + b

let myFunction = {
    Function = (fun (a,b) -> add a b)
}

你为什么需要这个?我的意思是,在你达到这个目标后,你打算如何使用这种类型?不需要太深入的细节,大量的思考。我使用JSON源中的JToken压缩函数的任意数量的输入类型,将令牌转换为输入类型,然后使用正确类型的参数调用函数。为了更安全,我希望将所有这些限制为仅可用于返回特定类型的函数,该类型必须以特定的方式构造。考虑到最终目标,我建议将参数设置为元组而不是curry。这样,您的反射代码可以识别元组类型并使用正确类型的参数初始化它。这可能是目前为止最好的方法,谢谢。但是,它增加了将输入元组展平的复杂性。这只适用于具有一个输入参数的函数,正如我在问题的最后一个代码块中尝试显示的那样。Duh!好的,那么我建议Fyodors解决方案(如果适用)。
type Foo<'InputType, 'OutputType> = {
    Function: ('InputType -> 'OutputType)
}
type Foo<'InputType> = {
    Function: ('InputType -> int)
}

let add a b = a + b

let myFunction = {
    Function = (fun (a,b) -> add a b)
}