2012-06-19 62 views
3

虽然将部分函数传递到另一个函数并不重要,但如何从函数返回不同签名的部分函数?f#从函数返回部分函数

这里是我尝试的基本代码,再进行各种尝试,以得到它的工作:

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 
  1. 试图迫使以各种方式通用的返回签名,但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*) 
    
  2. 试图盒/拆箱:

    | "arrayintasc" -> box InitData.arrayIntAsc 
    

    这个编译,但拆箱尝试抛出一个运行时错误:

    Unhandled Exception: System.InvalidCastException: Unable to cast object of type '[email protected]' to type 'System.Collections.Generic.IEnumerable`1[System.Object]'

  3. 试图恢复部分功能的报价,但有类似的问题。如果我返回键入的引用,则返回不同的Expr签名也会遇到同样的问题。我可以返回无类型的引号,但是我必须知道在调用端返回的无类型表达式的签名。

  4. 被认为是反射,但基本上是相同的问题,需要知道实际的签名时,它需要调用。

  5. 也以各种方式尝试了上传部分功能。

+7

你能解释一下为什么你要这样做吗?你如何期待调用者使用'getInitDataFun'? – kvb

回答

1

我觉得无论这是你想要

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 

或我不清楚你问什么。

+0

也许我不是很清楚,我不想知道主叫方的签名。您的解决方案需要知道返回的签名才能执行沮丧行为。 –

+2

@Jack:F#是一个强大的静态类型语言 - 调用者_needs_知道它在调用什么。 – ildjarn

+1

@ildjam:是的。我想我通过向前推进不同签名功能来解决我的问题,而不是试图返回它们。我最初的意图和问题是命令性思维的痕迹。 –

2

最好的办法是改变静态成员都返回相同类型:

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 

可能化妆它通用:

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!