5

¿La "Restricción de valor" significa prácticamente que no hay una programación funcional de orden superior?¿La "Restricción de valor" significa prácticamente que no hay una programación funcional de orden superior?

Tengo el problema de que cada vez que trato de hacer un poco de HOP me atrapa un error de VR. Ejemplo:

let simple (s:string)= fun rq->1 
let oops= simple "" 

type 'a SimpleType= F of (int ->'a-> 'a) 
let get a = F(fun req -> id) 
let oops2= get "" 

y me gustaría saber si se trata de un problema de una aplicación prticular de VR o se trata de un problema general que no tiene solución en un lenguaje de tipo infered mutable que no incluye mutación en el sistema de tipo.

+7

¿Le importaría que reformular como una pregunta que tiene sentido? –

+0

No soy un experto en programación funcional, pero ¿no es esta restricción una característica de los lenguajes similares a ML que no comparten otros lenguajes funcionales (por ejemplo, Haskell)? Si es así, es posible que desee etiquetar su pregunta en consecuencia. –

+0

mi pregunta es: ¿la mutabilidad significa una realidad virtual estricta en los lenguajes funcionales inferidos? – Sadache

Respuesta

2

No sabía los detalles de la restricción de valor, por lo que busqué y encontré this article. Aquí está la parte relevante:

Obviamente, no vamos a escribir la expresión rev [] en un programa, por lo que no es particularmente importante que no sea polimórfico. Pero, ¿y si creamos una función usando una llamada a función? Con funciones al curry, lo hacemos todo el tiempo:

- val revlists = map rev; 

Aquí revlists deben ser polimórficos, pero la restricción de valor nos puede confundir:

- val revlists = map rev; 
stdIn:32.1-32.23 Warning: type vars not generalized because of 
    value restriction are instantiated to dummy types (X1,X2,...) 
val revlists = fn : ?.X1 list list -> ?.X1 list list 

Afortunadamente, hay un truco simple que podemos utilizar hacer revolistas polimórficos Podemos reemplazar la definición de revlists con

- val revlists = (fn xs => map rev xs); 
val revlists = fn : 'a list list -> 'a list list 

y ahora todo funciona bien, ya que (fn => xs xs mapa rev) es un valor sintáctico. (equivalente, que podría haber utilizado la sintaxis diversión más comunes:.

- fun revlists xs = map rev xs; 
val revlists = fn : 'a list list -> 'a list list 

con el mismo resultado) En la literatura, el truco de la sustitución de una expresión de función de valor e con (fn x => Ex) es conocido como expansión de eta Se ha encontrado empíricamente que la expansión eta por lo general es suficiente para hacer frente a la restricción de valor.

Para resumir, no parece que la programación de orden superior esté restringida tanto como la programación sin puntos. Esto podría explicar algunos de los problemas que tengo al traducir el código Haskell a F #.


Editar: En concreto, aquí es cómo fijar el primer ejemplo:

let simple (s:string)= fun rq->1 
let oops= (fun x -> simple "" x)  (* eta-expand oops *) 

type 'a SimpleType= F of (int ->'a-> 'a) 
let get a = F(fun req -> id) 
let oops2= get "" 

no he descubierto que el segundo todavía porque el constructor de tipos está recibiendo en el camino.

+0

pero mi segundo ejemplo no es un punto libre, solo una función simple en un tipo.Y NO puedo hacer eta reduction (y de todos modos me parece feo): s – Sadache

+0

'(fun req -> id)' faltan algunos argumentos: '(fun req x -> id x)' es la versión eta-expanded. Sin embargo, ambas funciones son aún de orden superior. (Pero el segundo no resuelve la restricción de valor, al menos en OCaml.) –

+0

sí, no resuelve el VR. Por lo tanto, no se trata de puntos libres sino de funciones que devuelven funciones. – Sadache

6

¿La "Restricción de valor" significa que no hay una programación funcional de orden superior?

Absolutely not! La restricción de valor apenas interfiere con la programación funcional de orden superior. Lo que no hacer es restringir algunas aplicaciones de polimórficos funciones — no funciones de orden superior — en el nivel superior.


Veamos su ejemplo. Su problema es que oops y oops2 son ambos la función de identidad y tienen tipo forall 'a . 'a -> 'a. En otras palabras, cada uno es un valor polimórfico. Pero el lado derecho no es un llamado "valor sintáctico"; es una aplicación de función. (Una aplicación de función no puede devolver un valor polimórfico porque si fuera así, podría construir una función hacky usando referencias mutables y listas que podrían subvertir el sistema de tipo; es decir, podría escribir una función de terminación tipo forall 'a 'b . 'a -> 'b.

casos Afortunadamente, en casi todos los prácticos, el valor polimórfico en cuestión es una función, y se pueden definir por ETA en expansión:

let oops x = simple "" x 

Este idioma parece que tiene algún costo en tiempo de ejecución, pero dependiendo de el inliner y el optimizador, que pueden ser eliminados por el compilador —, es solo el tipoche que tiene problemas.

El ejemplo oops2 es más problemático porque usted tiene que hacer y deshacer el valor constructor:

let oops2 = F(fun x -> let F f = get "" in f x) 

Este es un buen pero más tedioso, pero la función anónima fun x -> ... es un valor sintáctico y F es una constructor de tipo de datos, y un constructor aplicado a un valor sintáctico es también un valor sintáctico, y Bob es tu tío. El embalaje y desembalaje de F se compilará en la función de identidad, por lo que oops2 va a compilar en exactamente el mismo código de máquina que oops.

Las cosas son aún más desagradables cuando se desea que un cálculo en tiempo de ejecución devuelva un valor polimórfico como None o []. Como insinuado por Nathan Sanders, puede ir en contra de la restricción de valor con una expresión tan simple como rev []:

Standard ML of New Jersey v110.67 [built: Sun Oct 19 17:18:14 2008] 
- val l = rev []; 
stdIn:1.5-1.15 Warning: type vars not generalized because of 
    value restriction are instantiated to dummy types (X1,X2,...) 
val l = [] : ?.X1 list 
- 

Nada de orden superior no! Y sin embargo, la restricción de valor se aplica.

En la práctica la restricción de valor no presenta ninguna barrera para la definición y el uso de las funciones de orden superior; simplemente expandes eta

+0

Aunque lo que dijo sobre la realidad virtual es cierto en general, no respondió la pregunta de OP. En primer lugar, oops2 expandir eta no funcionará si lee la otra respuesta o si prueba el programa usted mismo. En segundo lugar, creo que OP ya entendía la razón detrás de esta restricción, y quería saber si hay alguna solución mejor. –

+0

@Wei eso se debe a que no comprendí totalmente la pregunta de OP (y aún no lo hago). Pero he tratado de aclarar. –

+0

'get' es una función única, por lo que no puede escribir' let oops2 x = get "" x'. –

2

Aquí está the answer to this question en el contexto de F #. Para resumir, en F # pasar un argumento de tipo a una función genérica (= polimórfica) es una operación en tiempo de ejecución, por lo que en realidad es seguro de generalizar (como en, no se bloqueará en tiempo de ejecución). Sin embargo, el comportamiento del valor así generalizado puede ser sorprendente.

Para este ejemplo en particular en Fa #, se puede recuperar la generalización con una anotación de tipo y un parámetro de tipo explícito:

type 'a SimpleType= F of (int ->'a-> 'a) 
let get a = F(fun req -> id) 
let oops2<'T> : 'T SimpleType = get "" 
Cuestiones relacionadas