3

部分関数を別の関数に渡すのは簡単ですが、関数からさまざまなシグネチャの部分関数を返​​すにはどうすればよいでしょうか?

これが私が試みている基本的なコードであり、その後にそれを機能させるためのさまざまな試みが続きます:

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
    

    これはコンパイルされますが、ボックス化を解除しようとするとランタイム エラーがスローされます。

    未処理の例外: System.InvalidCastException: 型のオブジェクトを型にキャストできませ'RangeInt32@4819-2''System.Collections.Generic.IEnumerable`1[System.Object]'

  3. 部分関数を引用符として返そうとしましたが、同様の問題がありました。タイプされた引用符を返した場合、異なる Expr 署名を返すことで同じ問題が発生しました。型なしの引用符を返すことはできますが、呼び出し側で、返された型なしの式の署名を知る必要があります。

  4. リフレクションと見なされますが、呼び出すときに実際の署名を知る必要があるという基本的に同じ問題です。

  5. 部分関数もさまざまな方法でアップキャストしてみました。

4

2 に答える 2

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!
于 2012-06-19T18:29:44.627 に答える
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

または、あなたが何を求めているのかわかりません。

于 2012-06-19T18:26:59.637 に答える