2011-01-11 9 views
7

después de algún juego en torno F cuentan con limitaciones # miembros y función de escritura de la siguiente manera:F limitaciones # miembros +^a byref parámetros

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

que funciona perfectamente bien:

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

Estoy intentando escribir other func tryParse, que usa el método estático TryParse y envuelve el resultado del análisis en el tipo 'a option para un mejor soporte en F #. Algo como esto no se compila:

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 

El error es: FS0001

de error: Esta expresión se espera que tenga tipo byref < 'a> pero aquí tiene tipo 'a ref

F # ref -células d oesn't work too:

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 

¿Qué estoy haciendo mal?

+0

Ay, creo esto es un error ... también, 'TryParse: string -> bool *^a' no funciona. –

+0

Esto parece estar arreglado en F # 3.0. – kvb

Respuesta

4

ACTUALIZACIÓN

Esto parece ser fijo en Fa # 3.0.

vieja respuesta:

Estoy de acuerdo con el comentario de Stephen que es más probable un error. Hay muchas limitaciones en los tipos byref, por lo que no me sorprende en particular que no jueguen bien con las restricciones de los miembros. He aquí un (feo) solución utilizando la reflexión:

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" 
1

Creo que es un error demasiado, algo con limitaciones miembros y byref tipos. Puedo hacer una versión de la reflexión un poco menos feo por los cambios en la firma de la restricción miembro de:

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 

Éste es muy estrecha:

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 

pero me da un error de FS0421: La dirección de la la variable 'x' no se puede usar en este punto cuando intento compilarlo.

1

Esto compila pero aún no funciona como se esperaba:

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> 

en este caso específico, en lugar de utilizar la reflexión que acabo Reproducía TryParse de Parse en f #

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> 
+0

Levanté esto a [email protected] –