ventajas tutorial fsharpforfunandprofit example español ejemplos desventajas acorde f# visual-studio-2012 f#-3.0 active-pattern

tutorial - f# vs c#



Patrón activo roto en F#3.0 (4)

Este patrón activo se compila con F # 2.0:

let (|Value|_|) value = // ''a -> ''T option match box value with | :? ''T as x -> Some x | _ -> None

pero, en F # 3.0, emite el error:

Patrón activo ''| Valor | _ |'' tiene un tipo de resultado que contiene variables de tipo que no están determinadas por la entrada. La causa común es un [sic] cuando no se menciona un caso de resultado, por ejemplo, ''let (| A | B |) (x: int) = A x''. Esto se puede solucionar con una restricción de tipo, por ejemplo, ''let (| A | B |) (x: int): Choice = A x''

Lo intenté:

let (|Value|_|) value : ''T option = ...

y:

let (|Value|_|) (value: ''U) = ...

¿Cómo se puede arreglar?

Entornos: Visual Studio 2012 (RTM) y FSI v11.0.50727.1

EDITAR: Aquí hay una reproducción más simple:

let (|X|) x = unbox x


Hubo un error en el compilador de F # 2.0 donde el compilador realizó análisis incorrectos y generación de código incorrecto para ciertos Patrones Activos con variables de tipo gratuitas en el resultado; una reproducción simple es

let (|Check|) (a : int) = a, None //let (|Check|) (a : int) = a, (None : int option) let check a = match a with | Check (10, None) -> System.Console.WriteLine "10" | Check (20, None) -> System.Console.WriteLine "20" check 10 check 20

que genera una advertencia extraña en tiempo de compilación y compila en código aparentemente incorrecto. Supongo que nuestro intento de arreglar este error (y restringir algunos casos locos) en F # 3.0 también rompió algunos códigos legales como daño colateral de la corrección.

Archivaré otro error, pero para F # 3.0, parece que necesitará usar una de las soluciones alternativas mencionadas en otras respuestas.


No instalé la nueva versión todavía, pero estoy de acuerdo con que esto parece un poco sospechoso. Supongo que puede haber una buena razón para esta restricción, pero su ejemplo en la otra pregunta parece bastante convincente.

Como solución alternativa, creo que podría ser útil agregar un parámetro testigo (que no se usa, pero da pistas sobre el tipo de resultado):

let (|Value|_|) (witness:unit -> ''T) value : ''T option = match box value with | :? ''T as x -> Some x | _ -> None

Por supuesto, esto hace que el uso sea un poco más feo, porque tienes que llegar a algún argumento. En el ejemplo anterior, utilicé el testigo de la unit -> ''T de tipo unit -> ''T , con la esperanza de que se pueda compilar lo siguiente:

let witness () : ''T = failwith "!" match box 1 with | Value witness 1 -> printfn "one"

Si eso no funciona, entonces probablemente pueda intentar usar el parámetro testigo de tipo ''T (pero luego debe proporcionar una función real, en lugar de solo una función genérica).


Consulte mi respuesta a su otra pregunta para obtener algunas ideas sobre cómo solucionar el problema y una de las razones por las cuales dichos patrones activos pueden ser indeseables. No estoy seguro si el cambio fue intencionado.


para completar, una solución más:

type Box<''R> = Box of obj let (|Value|_|) ((Box x) : Box<''R> ) : ''R option = match x with | :? ''R as x -> Some x | _ -> None let check t = match Box t with | Value 1 -> printfn "one" | Value 2 -> printfn "two" check 1 // one check 2 // two

sin embargo, aún sufrirá el problema mencionado por @kvb en otro hilo . Personalmente preferiré la versión de @ kvb con un patrón activo parametrizado.