f#从函数返回部分函数

f#从函数返回部分函数,f#,F#,虽然将一个部分函数传递给另一个函数很简单,但是如何从一个函数返回具有不同签名的部分函数呢 以下是我正在尝试的基本代码,然后是各种尝试使其正常工作: type InitData() = static member arrayIntAsc count = [|1..count|] static member seqIntAsc count = {1..count} static member listIntAsc count = [1..count] (*more

虽然将一个部分函数传递给另一个函数很简单,但是如何从一个函数返回具有不同签名的部分函数呢

以下是我正在尝试的基本代码,然后是各种尝试使其正常工作:

type InitData() =
    static member arrayIntAsc count = [|1..count|] 
    static member seqIntAsc count = {1..count}
    static member listIntAsc count = [1..count]
    (*more diverse signatures*)

module x =
    let getInitDataFun (initData:string) =
        match initData.ToLower() with
        | "arrayintasc" -> InitData.arrayIntAsc
        | "seqintasc" -> InitData.seqIntAsc
        | "listintasc" -> InitData.listIntAsc
        (*more diverse signatures*)
        | _ -> failwithf "InitData function %s not recognized" initData
  • 尝试以各种方式强制使用通用返回签名,但F#3.0始终将getInitDataFun返回签名强制为第一个匹配的签名:

    let getInitDataFun (initData:string) : 'a -> 'b  = ...
    let getInitDataFun (initData:string) : _ -> _  = ...
    let getInitDataFun (initData:string) : int -> #(int seq)  = ...
    let getInitDataFun (initData:string) : int -> #('a seq)  = ...
    (*even if I could get (int -> #(int seq)) to work, I would like to return
      signatures not in this pattern too*)
    
  • 试过的盒子/取消盒子:

    | "arrayintasc" -> box InitData.arrayIntAsc
    
    这会编译,但取消装箱尝试会引发运行时错误:

    未处理的异常:System.InvalidCastException:无法强制转换类型为
    的对象RangeInt32@4819-2'
    输入
    'System.Collections.Generic.IEnumerable`1[System.Object]'

  • 尝试将部分函数作为引用返回,但遇到类似问题。如果我返回键入的报价,我会遇到返回不同Expr签名的相同问题。我可以返回非类型化的引用,但是我必须知道在调用端返回的非类型化表达式的签名

  • 考虑了反射,但基本上是相同的问题,需要知道调用时的实际签名

  • 也尝试过以各种方式向上转换部分函数


  • 我想这是你想要的

    type InitData() = 
        static member arrayIntAsc count = [|1..count|]  
        static member seqIntAsc count = {1..count} 
        static member listIntAsc count = [1..count] 
        (*more diverse signatures*) 
    
    let getInitDataFun (initData:string) : obj = 
        match initData.ToLower() with 
        | "arrayintasc" -> box InitData.arrayIntAsc 
        | "seqintasc" -> box InitData.seqIntAsc 
        | "listintasc" -> box InitData.listIntAsc 
        (*more diverse signatures*) 
        | _ -> failwithf "InitData function %s not recognized" initData 
    
    let a = ((getInitDataFun "arrayintasc") :?> int->int[]) 20
    printfn "%A" a
    

    或者我不清楚您在问什么。

    您最好将静态成员更改为所有返回相同类型:

    type InitData() =
        static member arrayIntAsc count = seq [|1..count|] 
        static member seqIntAsc count = {1..count}
        static member listIntAsc count = seq [1..count]
    
    或者使用执行强制转换的函数包装它们:

    let getInitDataFun (initData:string) =
        let asSeq f x = f x :> seq<_>
        match initData.ToLower() with
        | "arrayintasc" -> asSeq InitData.arrayIntAsc
        | "seqintasc" -> InitData.seqIntAsc
        | "listintasc" -> asSeq InitData.listIntAsc
    

    你能解释一下你为什么要这样做吗?您希望调用方如何使用
    getInitDataFun
    ?也许我不太清楚,我不想知道调用方的签名。您的解决方案需要知道返回的签名才能进行向下转换。@Jack:F#是一种强静态类型语言——调用者需要知道它在调用什么。@ildjam:yep。我认为我解决了正确解决问题的方法是将多样性签名的函数向前线程化,而不是试图返回它们。我的初衷和问题是命令式思维的残余。
    let getInitDataFun<'T when 'T :> seq<int>> (initData:string) : (int -> 'T) =
        match initData.ToLower() with
        | "arrayintasc" -> (box >> unbox) InitData.arrayIntAsc
        | "seqintasc" -> (box >> unbox) InitData.seqIntAsc
        | "listintasc" -> (box >> unbox) InitData.listIntAsc
    
    let f = getInitDataFun "arrayintasc"
    let x : int list = f 10 //BOOM!