functions funciones from foldr foldl argument haskell lambda evaluation

funciones - haskell main



Comportamiento contradictorio de las funciones de Lambda (2)

Usando las siguientes definiciones:

lenDigits n = length (show n) factorial n = product [1..n]

Yo evalúo lo siguiente

Prelude> ((lenDigits . factorial) 199) <= 199 False Prelude> (/i -> ((lenDigits . factorial) i) <= i) 199 True

¿Cuál es la razón de tal comportamiento? Según lo veo, la primera expresión es la misma que la segunda expresión con las lambdas reducidas.


Aquí hay una explicación paso a paso de esta pregunta.

Comencemos con:

((lenDigits . factorial) 199) <= 199

De acuerdo con el Informe Haskell ...

Un literal entero representa la aplicación de la función fromInteger al valor apropiado de tipo Integer .

Eso significa que nuestra primera expresión es en realidad:

((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (fromInteger (199 :: Integer))

Por sí mismo, fromInteger (199 :: Integer) tiene el tipo polimórfico Num a => a . Ahora tenemos que ver si este tipo está especializado en el contexto de la expresión completa. Tenga en cuenta que, hasta que encontremos una razón para que no sea así, deberíamos suponer que los tipos polimórficos de las dos ocurrencias de fromInteger (199 :: Integer) son independientes ( Num a => a y Num b => b , si será).

lenDigits es Show a => a -> Int , y entonces el ...

(lenDigits . factorial) (fromInteger (199 :: Integer))

... a la izquierda del <= debe ser un Int . Dado que (<=) es Ord a => a -> a -> Bool , el fromInteger (199 :: Integer) a la derecha de <= también tiene que ser un Int . La expresión completa se convierte en:

((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (199 :: Int)

Mientras que el segundo 199 se especializó en Int , el primero sigue siendo polimórfico. A falta de otras anotaciones de tipo, el valor predeterminado lo hace especializarse en Integer cuando usamos la expresión en GHCi. Por lo tanto, finalmente obtenemos:

((lenDigits . factorial) (199 :: Integer)) <= (199 :: Int)

Ahora, a la segunda expresión:

(/i -> ((lenDigits . factorial) i) <= i) 199

Por el mismo razonamiento utilizado anteriormente, (lenDigits . factorial) i (a la izquierda de <= ) es un Int , y entonces i (a la derecha de <= ) también es un Int . Siendo así, tenemos ...

GHCi> :t /i -> (lenDigits . factorial) i <= i /i -> (lenDigits . factorial) i <= i :: Int -> Bool

... y por lo tanto, aplicándolo a 199 (que en realidad es de fromInteger (199 :: Integer) ) lo especializa en int, dando:

((lenDigits . factorial) (199 :: Int)) <= (199 :: Int)

Los primeros 199 ahora son Int lugar de Integer . factorial (199 :: Int) desborda el tipo de Int tamaño fijo, lo que lleva a un resultado falso. Una forma de evitarlo sería introducir un contenido explícito de parte de un fromInteger para obtener algo equivalente al primer escenario:

GHCi> :t /i -> (lenDigits . factorial) i <= fromInteger i /i -> (lenDigits . factorial) i <= fromInteger i :: Integer -> Bool GHCi> (/i -> (lenDigits . factorial) i <= fromInteger i) 199 False


Porque en la primera expresión, el primer 199 tiene tipo Integer y el segundo tiene valor Int . Pero en la segunda expresión, ambos tienen el tipo Int y el factorial 199 no se puede representar con el tipo Int .