2012-08-15 12 views
8

Este patrón activo compila con F # 2.0:patrón activa roto en F # 3.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:

Active pattern '|Value|_|' has a result type containing type variables that are not determined by the input. The common cause is a [sic] when a result case is not mentioned, e.g. 'let (|A|B|) (x:int) = A x'. This can be fixed with a type constraint, e.g. 'let (|A|B|) (x:int) : Choice = A x'

Probé:

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

y:

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

¿Cómo se puede arreglar?

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

EDIT: He aquí una repro más simple:

let (|X|) x = unbox x 
+0

Funciona bien para mí, Visual Studio 2012 RC actualizado, 'Microsoft (R) F # 3.0 Interactive build 11.0.50522.1'. Al ver el error, todavía creo que debería funcionar (como lo hace). El ejemplo en el error ('let (| A | B |) (x: int) = A x') de hecho presenta el error que ha publicado. –

+1

'F # 2.0 Interactive build 4.0.40219.1' da exactamente los mismos resultados. –

+0

Lo siento, debería haber sido más específico sobre el medio ambiente. He actualizado la pregunta. – Daniel

Respuesta

4

Hubo un error en el compilador 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 libre 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 se compila en un 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 tendrá que utilizar una de las soluciones alternativas mencionadas en otras respuestas.

+0

¿Se ha corregido esto para F # 3.1? –

3

que no ha instalado la nueva versión todavía, pero estoy de acuerdo este se ve 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, creo que la adición de un parámetro testigo (que no se utiliza, pero que señala cuál es el tipo del resultado va a ser) podría funcionar:

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

Por supuesto, esto hace que la usa un poco más feo, porque necesitas llegar a algún argumento. En lo anterior, se utiliza testimonio de tipo unit -> 'T, con la esperanza de que el siguiente podría compilar:

let witness() : 'T = failwith "!" 

match box 1 with 
| Value witness 1 -> printfn "one" 

Si eso no funciona, entonces es probable que pueda tratar con el parámetro testigo de tipo 'T (pero luego se va a proporcionar una función real, en lugar de solo una función genérica).

+0

Gracias por la No puedo imaginar una "buena razón" para romper algo que funciona en una versión anterior (y es útil). :-) – Daniel

+0

La solución en [mi respuesta] (http://stackoverflow.com/a/11990910/162396) (inspirado en kvb) a una pregunta de seguimiento no requiere el parámetro 'testigo 'y conserva el uso original. – Daniel

0

Consulte mi answer en su otro question para obtener algunas ideas sobre cómo solucionar el problema y una razón por la que dichos patrones activos pueden ser indeseables. No estoy seguro si el cambio fue intencionado.

2

para la mayor abundamiento, una más solución:

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, todavía van a sufrir el problema mencionado por @kvb en another thread. Personalmente preferiré la versión de @ kvb con un patrón activo parametrizado.