Comprender los errores de restricción de valor de F #

No entiendo cómo funciona la Restricción de valor en F #. He leído la explicación en la wiki y en la documentación de MSDN . Lo que no entiendo es:

  1. Por qué, por ejemplo, esto me da un error de Restricción de valor (tomado de esta pregunta):

    let toleq (e:float) ab = (abs ( a - b ) ) < e 

    Pero eso no:

     let toleq e (a:float) b = (abs ( a - b ) ) < e 
  2. Esto se generaliza bien …

     let is_bigger ab = a < b 

    pero esto no es (se especifica como int):

     let add ab = a + b 
  3. Por qué las funciones con parámetros implícitos generan Restricción de valor:

    esta:

     let item_count = List.fold (fun acc _ -> 1 + acc) 0 

    vs esto:

     let item_count l = List.fold (fun acc _ -> 1 + acc) 0 l 

    (Tenga en cuenta que, si uso esta función en un fragmento de código, el error de VR desaparecerá, pero luego la función se especificará para el tipo que la utilicé, y quiero que se generalice)

¿Como funciona?

(Estoy usando el último F #, v1.9.6.16)

EDITAR

La información mejor / reciente está aquí: Mantener la función parcialmente aplicada genérica

(original a continuación)

Creo que una cuestión pragmática no es tratar de entender esto demasiado profundamente, sino más bien conocer un par de estrategias generales para superar la realidad virtual y seguir con su trabajo. Es un poco como una respuesta ‘cop out’, pero no estoy seguro de que tenga sentido pasar el tiempo comprendiendo las intracaias del sistema de tipo F # (que continúa cambiando de manera menor de una versión a otra) aquí.

Las dos estrategias principales que defendería son estas. En primer lugar, si está definiendo un valor con un tipo de función (escriba con una flecha ‘->’), asegúrese de que sea una función sintáctica al hacer una conversión eta :

 // function that looks like a value, problem let tupleList = List.map (fun x -> x,x) // make it a syntactic function by adding argument to both sides let tupleList l = List.map (fun x -> x,x) l 

En segundo lugar, si todavía tiene problemas de realidad virtual / generalización, especifique la firma de tipo completa para decir lo que desea (y luego ‘retroceda’ como lo permite F #):

 // below has a problem... let toleq (e:float<_>) ab = (abs ( a - b ) ) < e // so be fully explicit, get it working... let toleq<[]'u> (e:float< 'u>) (a:float< 'u>) (b:float< 'u>) : bool = (abs ( a - b ) ) < e // then can experiment with removing annotations one-by-one... let toleq<[]'u> e (a:float< 'u>) b = (abs ( a - b ) ) < e 

Creo que esas dos estrategias son el mejor consejo pragmático. Dicho esto, este es mi bash de responder a sus preguntas específicas.

  1. No lo sé.

  2. '>' es una función completamente genérica ('a ->' a -> bool) que funciona para todos los tipos, y por lo tanto is_bigger se generaliza. Por otro lado, '+' es una función 'en línea' que funciona en un puñado de tipos primitivos y una cierta clase de otros tipos; solo se puede generalizar dentro de otras funciones 'en línea'; de lo contrario, debe anclarse a un tipo específico (o por defecto a 'int'). (El método "en línea" de polymorphism ad-hoc es cómo los operadores matemáticos en F # superan la falta de "clases de tipos").

  3. Esta es la cuestión de la 'función sintáctica' que discutí anteriormente; 'compilemos en campos / propiedades que, a diferencia de las funciones, no pueden ser genéricas. Entonces, si quieres que sea genérico, hazlo funcionar. (Consulte también esta pregunta para otra excepción a esta regla).

Se introdujo la restricción del valor para abordar algunos problemas con el polymorphism en presencia de efectos secundarios. F # hereda esto de OCaml, y creo que existe una restricción de valores en todas las variantes ML. Aquí hay algunos enlaces más para que los lea, además de los enlaces que citó. Como Haskell es puro, no está sujeto a esta restricción.

En cuanto a sus preguntas, creo que la pregunta 3 está realmente relacionada con la restricción de valores, mientras que las dos primeras no lo están.

Nadie, incluidas las personas del equipo F #, conoce la respuesta a esta pregunta de manera significativa.

El sistema de inferencia tipo F # es exactamente como la gramática VB6 en el sentido de que el comstackdor define la verdad.

Desafortunado, pero cierto.