¿Cómo doy tipos genéricos de expresiones en una cláusula "dónde"?

(por favor disculpe el ejemplo horriblemente artificial)

Lo que quiero hacer es especificar tipos en la cláusula where:

somemap :: (a -> b) -> [a] -> [b]
somemap f xs = ys
  where
    some = take 5 xs :: [a]
    ys = map f some :: [b]

Pero esto provoca un error:

*Main> :load file.hs 
[1 of 1] Compiling Main             ( file.hs, interpreted )

fil.hs:15:18:
    Couldn't match expected type `a1' against inferred type `a'
      `a1' is a rigid type variable bound by
           an expression type signature at file.hs:15:25
      `a' is a rigid type variable bound by
          the type signature for `somemap' at file.hs:12:12
      Expected type: [a1]
      Inferred type: [a]
    In the second argument of `take', namely `xs'
    In the expression: take 5 xs :: [a]

file.hs:16:13:
    Couldn't match expected type `b1' against inferred type `b'
      `b1' is a rigid type variable bound by
           an expression type signature at file.hs:16:24
      `b' is a rigid type variable bound by
          the type signature for `somemap' at file.hs:12:17
    In the first argument of `map', namely `f'
    In the expression: map f some :: [b]
    In the definition of `ys': ys = map f some :: [b]
Failed, modules loaded: none.

Mientras que si solo especifico tipos concretos, sustituyendo Int por a y Bool por b, no hay problema:

somemap :: (Int -> Bool) -> [Int] -> [Bool]
somemap f xs = ys
  where
    some = take 5 xs :: [Int]
    ys = map f some :: [Bool]

Así que mi pregunta es la siguiente: ¿Cómo especifico tipos genéricos y restricciones de tipos en una cláusula where?

preguntado el 03 de mayo de 12 a las 16:05

1 Respuestas

Dentro de la where cláusula, las variables de tipo a y b se encuentran las Un nuevo tipo variables; Las variables de tipo no tienen alcance, por lo que cada firma de tipo tiene un nuevo suministro de ellas, como si estuvieran definidas en el nivel superior.

Si enciendes el ScopedTypeVariables extensión (poner {-# LANGUAGE ScopedTypeVariables #-} en la parte superior de su archivo), y cambie somemapdeclaración de tipo a:

somemap :: forall a b. (a -> b) -> [a] -> [b]

entonces el where definiciones de cláusulas que especificó funcionarán correctamente. creo que el foralls solo se requieren para la compatibilidad con versiones anteriores, por lo que el código que reutiliza variables de tipo en where las cláusulas para valores polimórficos no se rompen.

Si no quiere usar una extensión, la alternativa es definir funciones auxiliares feas para unificar los tipos, como asTypeOf.

contestado el 03 de mayo de 12 a las 16:05

El código en stackoverflow.com/questions/7408911/… es un buen ejemplo de la confusión que puede surgir de tales "funciones auxiliares feas". - John L

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.