2010-03-22 6 views
6

Après avoir joué avec haskell un peu je suis tombé sur cette fonction:Le système de type de Haskell traite une valeur numérique comme fonction?

Prelude Data.Maclaurin> :t ((+) . ($) . (+)) 
((+) . ($) . (+)) :: (Num a) => a -> (a -> a) -> a -> a 

(Data.Maclaurin est exporté par le paquet espace vectoriel.) Il faut donc un Num, une fonction, une autre Num et, finalement, les retours un Num. Quelle magie fait le travail suivant?

Prelude Data.Maclaurin> ((+) . ($) . (+)) 1 2 3 
6 

2 n'est évidemment pas une fonction (a-> a) ou est-ce que j'ai manqué quelque chose?

+0

http://www.haskell.org/haskellwiki/Num_instance_for_functions – sdcvvc

Répondre

16

Le module Data.NumInstances du même paquet defines une instance Num pour les fonctions qui renvoient les numéros:

instance Num b => Num (a->b) where 
    (+)   = liftA2 (+) 
    (*)   = liftA2 (*) 
    fromInteger = pure . fromInteger 
    ... 

Dans Haskell un entier littéral comme 2 est générique afin qu'il puisse représenter un nombre pour chaque instance de Num:

Prelude> :t 2 
2 :: (Num t) => t 

pour convertir un nombre réel du type requis dans un contexte spécifique, fromInteger du Num La classe est appelée.

Puisque le module auxiliaire mentionné ci-dessus définit une instance de Num pour les fonctions, 2 peuvent maintenant être converties en une fonction avec la méthode fromInteger il spécifiée. Donc ghci appelle fromInteger 2 pour obtenir la fonction requise comme second paramètre de la construction dans la question. L'expression entière arrive ensuite à évaluer à 6.

+0

De plus, * tous * foncteurs admettent ces cas applicatifs pour les classes numériques . Voir le paquet [applicative-numbers] (http://hackage.haskell.org/package/applicative-numbers) pour un moyen facile de définir de telles instances quel que soit le foncteur applicatif souhaité. – Conal

1

Vous avez de bonnes raisons d'être confus. En utilisant le module Data.NumInstances dans GHC (qui est chargé par Data.Maclaurin) il est possible de contraindre un Num à une fonction constante.

Prelude Data.NumInstances> :t (2 :: (Num a) => a -> a) 
(2 :: (Num a) => a -> a) :: (Num a) => a -> a 
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 0   
2 
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 1000 
2 

L'évaluation de l'expression est, essentiellement,

((+) . ($) . (+)) 1 2 3 = ((+) . ($) . (1+)) 2 3 
         = ((+) (1+)) 2 3 
         -- (+) is defined for functions that return a Num 
         = ((+) (1+) (\_ -> 2)) 3 
         = ((+2) . (1+)) 3 
         = 6 
+2

Non, ce n'est pas possible, sauf si vous avez chargé des modules non standard qui définissent une instance 'Num' pour' a -> a'. –

+1

Eh bien, putain, je pourrais jurer cela a fonctionné sans Data.Maclaurin chargé, mais il ne le fait pas. Comme @sth le souligne, cette magie est activée par Data.NumInstances. –

Questions connexes