¿Por qué Haskell no puede evitar la evaluación repetida sin la restricción de monomorfismo?

14

Acabo de terminar de aprender el otro día, y estaba tratando de dar sentido a la restricción de monomorfismo, como lo describe el Wiki de Haskell . Creo que entiendo cómo la MR puede evitar evaluaciones repetidas, pero no entiendo por qué esas evaluaciones repetidas no se pueden evitar por medios mucho más directos.

El ejemplo específico que tengo en mente es el que usa el wiki:

f xs = (len,len)
  where
    len = genericLength xs

donde genericLengthes de tipo Num a => [b] -> a.

Obviamente, genericLength xssolo necesita calcularse una vez para evaluar (len,len), ya que es la misma función con los mismos argumentos. Y no necesitamos ver ninguna invocación fpara saber eso. Entonces, ¿por qué Haskell no puede hacer esta optimización sin introducir una regla como el MR?

La discusión en esa página wiki me dice que tiene algo que ver con el hecho de que Numes una clase de tipos en lugar de un tipo concreto, pero aun así, ¿no debería ser obvio en tiempo de compilación que una función pura devolvería el mismo valor? -y, por lo tanto, el mismo tipo concreto de Num, cuando se les dan los mismos argumentos dos veces

Ixrec
fuente

Respuestas:

11

Es el mismo nombre de función, con los mismos argumentos, pero tipos e implementaciones de retorno potencialmente diferentes, porque es polimórfico. Eso significa que si se llama en un contexto que espera un (Int, MyWeirdCustomNumType)tipo de retorno, tiene que evaluarlo dos veces, porque la implementación de (+)in Intes completamente diferente de la implementación de (+)in MyWeirdCustomNumType. Necesita ejecutar código físicamente diferente en algún momento.

Por eso es importante que Numsea ​​una clase de tipo. Significa que tiene diferentes implementaciones para diferentes tipos. También significa que si festá en una biblioteca, no sabe en tiempo de compilación todas las combinaciones de tipos que podría necesitar devolver.

Entonces, sí, necesita ver las invocaciones de fpara saber qué tipos de retorno usar. La mayoría de las veces, es de esperar que sean iguales, por lo que ponen la restricción de monomorfismo por defecto. Se puede desactivar para esas raras ocasiones en que no lo hace. En la práctica, los programadores no tienden a dejar este tipo de situaciones para escribir inferencia de todos modos.

Karl Bielefeldt
fuente
No había considerado la posibilidad de f [] :: (Int, Float). Ahora tiene mucho sentido. Gracias.
Ixrec
1
It's the same function name, with the same arguments, but potentially different return types and implementations, because it's polymorphic.Creo que la mejor forma de verlo es que la instancia de la clase de tipos es efectivamente un argumento adicional genericLengthy el compilador no está convencido de que sean los mismos argumentos en ambas llamadas.
Doval
Pregunta lateral rápida Si MonomorphismRestriction está desactivado, pero luego hizo algo como a = uncurry (==) $ f [1, 2, 3]¿Podría optimizar ese sitio de llamadas para verificar solo la duración de [1, 2, 3]una vez? Si es así, estoy realmente confundido sobre lo que la restricción de monomorfismo realmente te está comprando, si no, ¿por qué no?
punto