simbolos - Alcance de Haskell en definiciones de funciones anidadas usando donde
imprimir en haskell (2)
Tengo un problema con el alcance de Haskell en where
definiciones. Cuando tengo la siguiente función f
, donde quiero pasar la x
a la función localmente definida f1
sin usarla explícitamente como parámetro, aparece un error que dice que el tipo de x
es incompatible con el de la salida de f1
. Aunque debería ser el mismo:
f :: Eq a => a -> [a] f x = f1 x where f1 :: Eq a => a -> [a] f1 y = [ x, y ]
El error es el siguiente:
Couldn''t match expected type `a1'' against inferred type `a'' `a1'' is a rigid type variable bound by the type signature for `f1'' at test.hs:4:11 `a'' is a rigid type variable bound by the type signature for `f'' at test.hs:1:8 In the expression: x In the expression: [x, y] In the definition of `f1'': f1 y = [x, y] Failed, modules loaded: none.
Sin embargo, cuando paso la x
como un parámetro adicional, como hice en el siguiente código con la función g
, funciona bien:
g :: Eq a => a -> [a] g x = g1 x x where g1 :: Eq a => a -> a -> [a] g1 x y = [ x, y ]
¿Hay alguna manera de hacer que el tipo a
en f
compatible con el tipo a
(o a1
) en f1
?
Dave está justo arriba. Otra forma de verlo es que aunque ambas firmas de tipo se refieren a la variable a
, en realidad no es la misma variable de tipo. En la notación Haskell-prime, ambas firmas pueden escribirse más explícitamente como:
forall a . Eq a => a -> [a]
lo que significa que para ambas funciones, pueden aceptar un argumento de cualquier tipo (dentro de la ecuación). Esto obviamente no es el caso aquí. En el estándar Haskell 98, la única opción es renunciar a la firma de tipo para f1
. Pero GHC (¿y otros?) Admiten variables de tipo de ámbito léxico . Para que pudieras escribir
{-# LANGUAGE ScopedTypeVariables #-}
f :: forall a. Eq a => a -> [a]
f x = f1 x
where
f1 :: a -> [a]
f1 y = [ x, y ]
y eso funcionaria bien
El problema con su código es la firma de tipo f1 de ámbito local. Especifica que f1 puede tomar cualquier tipo.
f1 :: Eq a => a -> [a]
A pesar de que esta es una función local, ha generalizado esta función para poder tomar un tipo que no existirá dentro de f, independientemente de lo que esta función reciba TIENE que provenir de f, por lo que la firma de tipo no es necesaria.
Simplemente quite la firma de tipo f1.
Editar: leer mi publicación de nuevo a mí mismo, es un poco claro. a in f1 es un tipo parametrizado que puede tomar cualquier cosa, pero los argumentos que se le pasan ya están enlazados en f. Así que esta función solo puede recibir lo que recibe su función principal, la firma de tipo que le está dando rompe esa regla. Espero que eso sea un poco más claro.