2012-05-03 8 views
7

(proszę wybaczyć strasznie wymyślony przykład)Jak podać typowe wyrażenia w klauzuli "where"?

Co chcę zrobić, to określić typy w którym aktualnie klauzuli:

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

Ale to powoduje błąd:

*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. 

Gdybym tylko określił konkretne typy, zastępując Int dla a i Bool dla b, nie ma problemu:

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

Więc moje pytanie brzmi: Jak określić typy generyczne i rodzaj ograniczeń w klauzuli where-?

Odpowiedz

15

Wewnątrz klauzuli where zmienne typu a i bnowe zmienne typu; Zmienne typu nie mają określonego zakresu, więc każdy podpis typu ma ich nowe źródło, tak jakby zostały zdefiniowane na najwyższym poziomie.

Jeśli włączysz rozszerzenia ScopedTypeVariables (umieścić {-# LANGUAGE ScopedTypeVariables #-} u góry pliku), a także zmienić deklarację typu somemap „s do:

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

następnie definicje klauzula where ty wyszczególnione będą działać poprawnie. Myślę, że forall s są wymagane tylko dla zgodności wstecznej, więc kod, który wykorzystuje zmienne typu w klauzulach where dla wartości polimorficznych, nie pęka.

Jeśli nie chcesz używać rozszerzenia, alternatywą jest zdefiniowanie brzydkich funkcji pomocnika w celu ujednolicenia typów, takich jak asTypeOf.

+1

Kod w http://stackoverflow.com/questions/7408911/haskell-magical-code-whats-going-on-here jest dobrym przykładem zamieszania, które może wyniknąć z takich "brzydkich funkcji pomocnika". –