Forum Programmation.autre inférence de type en Haskell

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
3
30
juil.
2014

Bonjour à tous
Aujourd'hui je faisais un petit peu de Haskell, histoire de découvrir quelque chose de nouveau, et je me frottais un peu aux histoires d'évaluation explicite avec les listes.
Histoire de commencer petit, je voulais faire une petite fonction qui ne me sorte pas de out of memory pour faire une somme toute bête.
Donc dans mon interpréteur GhCI (Haskell Platform) je fais:

import list.Data
let sum' liste = foldl' (+) 0 liste
:t sum'
sum' :: Num b => [b] -> b

Jusque là tout va bien. Ça marche avec des listes d'entiers, de réels, etc… comme prévu.
Après, je me dis "tiens on va condenser un peu"

let sum' = foldl' (+) 0
:t sum'
sum' :: [Integer] -> Integer

Gni ??? Bon, on teste avec l'expression sans let…

:t foldl' (+) 0
foldl' (+) 0 :: Num b => [b] -> b

Re-gni ??? Bon, et avec un lambda ?

let sum' = \x -> foldl' (+) 0 x
:t sum'
sum' :: [Integer] -> Integer

Comprends plus… Quelqu'un pourrait-il me dire pourquoi à un moment donné je perds la généricité ?
En général je donne le moins d'information possible sur le type, donc je ne comprends pas d'où vient cette spécialisation soudaine…

  • # Seulement dans l'interpréteur ghci

    Posté par  (site web personnel) . Évalué à 1. Dernière modification le 30 juillet 2014 à 12:31.

    Je pense que ghc et ghci essaient de spécialiser sous certaines conditions à un type le plus petit possible (sans doute pour des raisons de performances). Si tu écris let sum' = foldl' (+) 0 dans un fichier, dans lequel tu utilises ensuite cette fonction avec une liste de flottants, et que tu compiles avec ghc, tu n'auras pas les problèmes de ghci, car ghc voit d'avance tout le fichier avant de décider la spécialisation (dans ghci je suppose que tu n'as pas d'autre choix que de spécifier à la main la signature).

    • [^] # Re: Seulement dans l'interpréteur ghci

      Posté par  . Évalué à 1.

      Je viens de faire un test sous Arch, avec ghc 7.8.3, et il semblerait que cette spécialisation n'ait pas lieu. Les 2 écritures restent équivalentes.
      Donc c'est peut-être dû à ghc 7.6.2 ?

      • [^] # Re: Seulement dans l'interpréteur ghci

        Posté par  (site web personnel) . Évalué à 2.

        J'ai trouvé : c'est le «monomorphism restriction» qui est responsable, et il a été désactivé par défaut dans ghci dans la 7.8.1. Tu peux aussi le désactiver manuellement dans ghci avec :set -XNoMonomorphismRestriction.

        • [^] # Re: Seulement dans l'interpréteur ghci

          Posté par  . Évalué à 1.

          OK, j'y vois un peu plus clair effectivement…
          Il faut donc spécifier une signature quand cette restriction est active…
          Mais dans ce cas, pour ceci ne marche pas ?

          let sum' = foldl' (+) 0 :: Num a => [a] -> a
          :t sum'
          sum' :: [Integer] -> Integer

          Il faut absolument passer par le style déclaratif plutôt que par une expression ?

          • [^] # Re: Seulement dans l'interpréteur ghci

            Posté par  (site web personnel) . Évalué à 1. Dernière modification le 30 juillet 2014 à 19:35.

            Je ne suis pas du tout un spécialiste du système de types de haskell (ni de haskell tout court), donc je ne suis pas sûr, mais on dirait. En tous cas c'est une « feature » assez obscure de haskell. Ceci dit, c'est un problème qui, en dehors de ghci, a très peu de chances d'intervenir dans un vrai programme. Et même dans une expression, si tu écris let sum' = foldl (+) 0 in sum' [1.2,1.5] dans ghc (ou ghci) ne va pas spécialiser la fonction plus que nécessaire vu qu'il sait déjà que tu vas l'appliquer à une liste de flottants avant.

          • [^] # Re: Seulement dans l'interpréteur ghci

            Posté par  . Évalué à 2. Dernière modification le 30 juillet 2014 à 22:30.

            Ça ne marche pas parce que la restriction monomorphique est sur le paramètre de sum', pas celui de foldl' (+) 0

            Dans cette page : http://www.haskell.org/haskellwiki/Monomorphism_restriction

            Tu te trouve dans le cas :

            -- This is not allowed
            f4 = show

            show est polymorphe, mais la restriction est sur le paramètre de f4

            Tu dois typer sum'

            let sum' :: Num a => [a] -> a
                sum' = foldl' (+) 0

            La restriction monomorphique est vraiment moche…

            Please do not feed the trolls

            • [^] # Re: Seulement dans l'interpréteur ghci

              Posté par  . Évalué à 2.

              haaa trop tard pour éditer, je voulais préciser la syntaxe pour GHCI :

              > let  { sum' :: Num a => [a] -> a ; sum' = foldl (+) 0 }
              > :t sum'
              sum' :: Num a => [a] -> a

              Please do not feed the trolls

              • [^] # Re: Seulement dans l'interpréteur ghci

                Posté par  . Évalué à 1.

                Merci pour la réponse, c'est effectivement plus clair.
                Une chose en amenant une autre, j'ai commencé à lire plus en détail sur ce "monomorphism reduction", et je suis tombé sur d'autres choses que je ne trouve même pas mentionnées dans les livres du genre "Real World Haskell", à savoir scoped types, pattern type definition, etc… Ce dernier me laisse particulièrement perplexe aussi: il est dit que c'est complètement orthogonal au type definition que j'utilise d'habitude, mais j'ai beaucoup de mal à voir la valeur ajoutée. Quoi qu'il en soit, c'est un peu la jungle dans toutes ces extensions GHC !

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.