9

F#メンバーの制約機能と書き込み機能を試してみた後、次のようになります。

let inline parse< ^a when ^a : (static member Parse: string -> ^a) > s =
    (^a: (static member Parse: string -> ^a) s)

それは完全にうまく機能します:

let xs = [ "123"; "456"; "999" ] |> List.map parse<int>

tryParse静的メソッドを使用しTryParse、解析結果を型にラップし'a optionてF#でのサポートを向上させる、他の関数を作成しようとしています。このようなものはコンパイルされません:

let inline tryParse s =
    let mutable x = Unchecked.defaultof< ^a>
    if (^a: (static member TryParse: string * ^a byref -> bool) (s, &x))
        then Some x else None

エラーは次のとおりです。

エラーFS0001:この式のタイプは byref <'a>であると予想されて いましたが、ここではタイプ ' arefです。

F#refセルも機能しません:

let inline tryParse s =
    let x = ref Unchecked.defaultof< ^a>
    if (^a: (static member TryParse: string * ^a byref -> bool) (s, x))
        then Some x else None

私は何が間違っているのですか?

4

3 に答える 3

6

アップデート

これはF#3.0で修正されているようです。

古い答え:

おそらくバグであるというスティーブンのコメントに同意します。byrefタイプには多くの制限があるため、メンバーの制約でうまく機能しないことは私にとって特に驚くべきことではありません。リフレクションを使用した(醜い)回避策は次のとおりです。

type parseDel<'a> = delegate of string * 'a byref -> bool

type Parser< ^a when ^a : (static member TryParse: string * ^a byref -> bool)> private ()=
  static let parser = System.Delegate.CreateDelegate(typeof<parseDel<'a>>, typeof<'a>.GetMethod("TryParse", [|typeof<string>; typeof<'a>.MakeByRefType()|])) :?> parseDel<'a>
  static member inline ParseDel = parser

let inline tryParse (s:string) =
  let mutable x = Unchecked.defaultof< ^a>
  if Parser<_>.ParseDel.Invoke(s, &x) then
    Some x
  else None

let one : int option = tryParse "1"
于 2011-01-11T14:44:28.130 に答える
2

これはコンパイルされますが、それでも期待どおりに機能しません。

let inline tryParse< ^a when ^a: (static member TryParse: string -> ^a ref -> bool) > s =
  let x = ref Unchecked.defaultof< ^a>
  match (^a: (static member TryParse: string -> ^a ref -> bool )  (s, x)) with
    | false -> None
    | true -> Some(!x)

// returns [Some 0; Some 0; Some 0; null], so our tryParse is not retrieving the value from the ref
let xs = [ "1"; "456"; "999"; "a" ] |> List.map tryParse<int>

この特定のケースでは、リフレクションを使用するのではなく、f#のParseからTryParseを再作成します。

let inline tryParse< ^a when ^a: (static member Parse: string -> ^a) > s =
  try  
    Some(^a: (static member Parse: string -> ^a)  s)
  with
    | exn -> None

let xs = [ "1"; "456"; "999"; "a" ] |> List.map tryParse<int>
于 2011-02-05T08:53:43.060 に答える
2

これもバグだと思います。メンバーの制約とbyrefタイプがあります。メンバー制約の署名を変更することで、少し醜い反射バージョンを作成できます。

let inline tryParse<'a when 'a : (static member TryParse : string -> 'a byref -> bool)>  s  =
    let args = [| s ; null |]
    if typeof<'a>
        .GetMethod("TryParse", [| typeof<string>; typeof< ^a>.MakeByRefType() |])
        .Invoke(null, args) = box true 
        then Some (args.[1] :?> 'a) 
        else None

これは非常に近いです:

let inline tryParse< ^a when ^a: (static member TryParse: string -> ^a byref -> bool)> s =
    let mutable x = Unchecked.defaultof<'a>
    if (^a: (static member TryParse: string -> ^a byref -> bool) (s, &x))
        then Some x else None

しかし、エラーFS0421が発生します。変数'x'のアドレスは、コンパイルしようとすると、この時点では使用できません。

于 2011-01-12T14:17:28.503 に答える