2009-12-01 5 views
7

Je viens de réaliser à quel point la petite fonction on peut être utile.Comment faire pour que Haskell calcule le type polymorphique correct?

Ex:

orderByLength = sortBy (compare `on` length) 

Mais malheureusement, les types inférées peut être un peu contre-intuitif.

Selon la définition même

f `on` g = \x y -> f (g x) (g y) 

on pourrait par exemple remplacer

(==) `on` length 

avec

\x y -> (length x) == (length y) 

Mais les deux ont différents types!

Le premier a [a] -> [a] -> Bool tandis que le second a le type correct, plus générique de [a] -> [b] -> Bool.

Ceci interdit les termes manifestement corrects comme (on (==) length) [1, 2, 3] ["a", "b", "c"] (qui devrait donner True mais qui échoue même à la vérification de type).

Je sais que cette restriction est due à l'utilisation de first-rank types, mais comment y remédier? Quelqu'un peut-il formuler une implémentation de on capable de traiter correctement les fonctions polymorphes (en utilisant des types de quantification/rank-n universels)?

Répondre

3
{-# LANGUAGE Rank2Types #-} 
on' :: (a -> a -> b) -> (forall d. c d -> a) -> c e -> c f -> b 
on' f g x y = f (g x) (g y) 

Il en résulte

 
Prelude> :t on' (==) 
on' (==) :: (Eq a) => (forall d. c d -> a) -> c e -> c f -> Bool 
Prelude> :t on' (==) length 
on' (==) length :: [e] -> [f] -> Bool 

D'autre part, cette signature fait également flip on' id illégale, ce qui est un peu moins que souhaitable.


{-# LANGUAGE TemplateHaskell #-} 
import Language.Haskell.TH 
onE f g = do 
    x <- newName "x" 
    y <- newName "y" 
    lamE [varP x, varP y] $ f `appE` (g `appE` varE x) `appE` (g `appE` varE y) 
 
Prelude> :set -XTemplateHaskell 
Prelude> $(onE [|(==)|] [|length|]) [1,2,3] ["a","b","c"] 
True 
Prelude> $(onE [|(==)|] [|id|]) 4 5 
False 
+0

chose Cool - Qu'est-ce 'C'? Un genre '* -> *'? Ah, c'est pour envelopper l'utilisation potentielle de '[type]' ... Pouvez-vous généraliser pour tout * type *? – Dario

+0

Cool, merci pour les deux idées – Dario

Questions connexes