drawing

Cours03 : le système de types¶

In [162]:
-- commentaire : directive pour le compilateur ghc 
:opt no-lint

Rappel : Haskell est fortement typé¶

In [163]:
"2" + 3
<interactive>:1:1: error:
    • No instance for (Num String) arising from a use of ‘+’
    • In the expression: "2" + 3
      In an equation for ‘it’: it = "2" + 3

La commande :t peut s'appliquer à n'importe quelle expression Haskell, c'est-à-dire à tout ce que l'on peut évaluer (une valeur, une lettre, un calcul, un if-then-else, une fonction, etc.).

Elle va répondre en donnant:

  • soit un type explicite, si c'est le seul possible, par exemple :
In [164]:
:t 'a'
'a' :: Char
  • soit un type polymorphe, qui est un type qui contient une ou plusieurs variables de type
In [19]:
:t []
[] :: forall a. [a]

Ici, le type signifie : une liste d'éléments de n'importe quel type que l'on nomme a. Tous les éléments de liste sont du même type. C'est similaire aux types génériques de Java (par exemple List<A>).

  • soit en indiquant une contrainte de classe, la plus générale possible. Par exemple :
In [165]:
:t 1
1 :: forall p. Num p => p

Ici, le type signifie : n'importe quel type que l'on nomme p, tel que p est membre de la classe Num (c'est la contrainte de classe). Autrement dit, l'expression peut avoir n'importe quel type, à condition que ce type soit "un nombre".

Ces notions seront détaillées dans les sections suivantes.

Les types explicites (ou concrets)¶

  • Bool — Valeurs logiques.
  • Char — Caractères individuels.
  • Int — Entiers à précision fixe.
  • Integer — Entiers à précision arbitraire.
  • Float — Nombres à virgule flottante à simple précision.
  • Double — Nombres à virgule flottante à double précision.
  • String — Chaînes de caractères (équivalent de [Char]).
  • les tuples et listes de types explicites
  • les fonctions dont les paramètres/types de retour sont explicites
In [6]:
:t "Ab"
:t ['A','b']
"Ab" :: [Char]
['A','b'] :: [Char]
In [168]:
:t (True, 'a', "cat")
(True, 'a', "cat") :: (Bool, Char, [Char])
In [8]:
:t ["True", "'a'", "cat"]
["True", "'a'", "cat"] :: [[Char]]
In [9]:
-- avec une annotation de type
:t ["True", "'a'", "cat"] :: [String]
["True", "'a'", "cat"] :: [String] :: [String]

Deux types d'entiers¶

In [10]:
x = 304140932017133780436126081660 :: Int
In [11]:
x
-4849135255881964932
In [12]:
x = 304140932017133780436126081660 :: Integer
In [13]:
x
304140932017133780436126081660
In [14]:
:t 304140932017133780436126081660
304140932017133780436126081660 :: forall p. Num p => p

Type vs. expression¶

Int n'est pas une expression :

In [96]:
:t Int
<interactive>:1:1: error: Data constructor not in scope: Int

C'est un type, on peut donc demander de quelle sorte (kind) de type il s'agit :

In [97]:
:k Int
Int :: *

Ici, * signifie que c'est un type explicite.

Les variables de type¶

C'est l'équivalent des paramètres de type (type parameter) en Java, c'est-à-dire les lettres entre <>.

In [91]:
-- quel est le type de la fonction head (pour les listes) ?
:t head
head :: forall a. [a] -> a

Ici, le type signifie : pour n'importe quel type que l'on nomme a, la fonction head prend en paramètre une liste d'éléments de type a et renvoie une valeur de type a.

Une même variable de type désigne le même type dans toute la signature.

In [92]:
:t fst
fst :: forall a b. (a, b) -> a

Ici, le type signifie : pour n'importe quels types que l'on nomme a et b, la fonction fst prend en paramètre un couple d'éléments de type (a,b) et renvoie une valeur de type a.

Les classes de type¶

Une classe de type, c'est (grosso modo) l'équivalent d'une interface en Java. C'est une façon de spécialiser une variable de type pour indiquer quel est le comportement qu'elle implémente.

In [109]:
-- quel est le type de la fonction (==) ?
:t (==)
(==) :: forall a. Eq a => a -> a -> Bool

Ici, le type signifie : pour n'importe quel type que l'on nomme a, tel que a est membre de la classe de type Eq, la fonction (==) prend deux expressions de type a en paramètre et renvoie un booléen.

In [112]:
-- quel est le type de la fonction (+) ?
:t (+)
(+) :: forall a. Num a => a -> a -> a

Ici, le type signifie : pour n'importe quel type que l'on nomme a, tel que a est membre de la classe de type Num, la fonction (+) prend deux expressions de type a en paramètre et renvoie un nombre de même type.

Num n'est pas une expression :

In [98]:
:t Num
<interactive>:1:1: error:
    • Data constructor not in scope: Eq
    • Perhaps you meant ‘EQ’ (imported from Prelude)

C'est un type, on peut donc demander de quelle sorte (kind) de type il s'agit :

In [114]:
:k Num
Num :: * -> Constraint

Ici, * -> Constraint signifie que Num est une classe applicable à un type et qui produit une contrainte.

In [118]:
-- type explicite vs. classe de type :
:k Int
:k Num
Int :: *
Num :: * -> Constraint

L'analogie avec les interfaces Java ne s'arrête pas là. Une classe de types définit un comportement : additionner, tester l’égalité, comparer l’ordre, énumérer, ...

Les types qui implémentent ce comportement sont des instances de cette classe.

La commande :i permet d'avoir toutes ces informations pour une classe de type.

In [119]:
:i Num
type Num :: * -> Constraint
class Num a where
(+) :: a -> a -> a
(-) :: a -> a -> a
(*) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
{-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-}
-- Defined in ‘GHC.Num’
instance Num Word -- Defined in ‘GHC.Num’
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Int -- Defined in ‘GHC.Num’
instance Num Float -- Defined in ‘GHC.Float’
instance Num Double -- Defined in ‘GHC.Float’
In [121]:
-- quel est le type de la fonction (==) ?
:t (==)
(==) :: forall a. Eq a => a -> a -> Bool
In [122]:
:i Eq
type Eq :: * -> Constraint
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
{-# MINIMAL (==) | (/=) #-}
-- Defined in ‘GHC.Classes’
instance Eq IHaskellSysIO.IOMode -- Defined in ‘GHC.IO.IOMode’
instance Eq IHaskellSysIO.SeekMode -- Defined in ‘GHC.IO.Device’
instance [safe] Eq IHaskellTH.Extension -- Defined in ‘GHC.LanguageExtensions.Type’
instance (Eq a, Eq b) => Eq (Either a b) -- Defined in ‘Data.Either’
instance Eq a => Eq [a] -- Defined in ‘GHC.Classes’
instance Eq Word -- Defined in ‘GHC.Classes’
instance Eq Ordering -- Defined in ‘GHC.Classes’
instance Eq Int -- Defined in ‘GHC.Classes’
instance Eq Float -- Defined in ‘GHC.Classes’
instance Eq Double -- Defined in ‘GHC.Classes’
instance Eq Char -- Defined in ‘GHC.Classes’
instance Eq Bool -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i, Eq j, Eq k, Eq l, Eq m, Eq n, Eq o) => Eq (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i, Eq j, Eq k, Eq l, Eq m, Eq n) => Eq (a, b, c, d, e, f, g, h, i, j, k, l, m, n) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i, Eq j, Eq k, Eq l, Eq m) => Eq (a, b, c, d, e, f, g, h, i, j, k, l, m) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i, Eq j, Eq k, Eq l) => Eq (a, b, c, d, e, f, g, h, i, j, k, l) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i, Eq j, Eq k) => Eq (a, b, c, d, e, f, g, h, i, j, k) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i, Eq j) => Eq (a, b, c, d, e, f, g, h, i, j) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i) => Eq (a, b, c, d, e, f, g, h, i) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h) => Eq (a, b, c, d, e, f, g, h) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g) => Eq (a, b, c, d, e, f, g) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f) => Eq (a, b, c, d, e, f) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d, Eq e) => Eq (a, b, c, d, e) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c, Eq d) => Eq (a, b, c, d) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b, Eq c) => Eq (a, b, c) -- Defined in ‘GHC.Classes’
instance (Eq a, Eq b) => Eq (a, b) -- Defined in ‘GHC.Classes’
instance Eq () -- Defined in ‘GHC.Classes’
instance Eq IHaskell.Display.DisplayData -- Defined in ‘IHaskell.IPython.Types’
instance Eq a => Eq (Maybe a) -- Defined in ‘GHC.Maybe’
instance Eq IHaskellTH.TypeFamilyHead -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Type -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.TyVarBndr -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.TySynEqn -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.TyLit -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Stmt -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.SourceUnpackedness -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.SourceStrictness -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Safety -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.RuleMatch -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.RuleBndr -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Role -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Range -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Pragma -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Phases -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.PatSynDir -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.PatSynArgs -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Pat -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Overlap -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.NameSpace -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Name -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.ModuleInfo -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Match -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Loc -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Lit -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Inline -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.InjectivityAnn -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Info -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Guard -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.FunDep -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Foreign -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.FixityDirection -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Fixity -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.FamilyResultSig -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Exp -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.DerivStrategy -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.DerivClause -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.DecidedStrictness -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Dec -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Con -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Clause -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Callconv -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Body -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.Bang -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.AnnTarget -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellTH.AnnLookup -- Defined in ‘Language.Haskell.TH.Syntax’
instance Eq IHaskellSysIO.NewlineMode -- Defined in ‘GHC.IO.Handle.Types’
instance Eq IHaskellSysIO.Newline -- Defined in ‘GHC.IO.Handle.Types’
instance Eq IHaskellSysIO.Handle -- Defined in ‘GHC.IO.Handle.Types’
instance Eq IHaskellSysIO.BufferMode -- Defined in ‘GHC.IO.Handle.Types’
instance Eq IHaskellSysIO.HandlePosn -- Defined in ‘GHC.IO.Handle’
instance Eq IHaskell.Display.Widget -- Defined in ‘IHaskell.Types’
instance Eq IHaskell.Display.Display -- Defined in ‘IHaskell.Types’
instance Eq Integer -- Defined in ‘integer-gmp-1.0.3.0:GHC.Integer.Type’
In [123]:
-- quel est le type de la fonction (<) ?
:t (<)
(<) :: forall a. Ord a => a -> a -> Bool
In [125]:
:i Ord
type Ord :: * -> Constraint
class Eq a => Ord a where
compare :: a -> a -> Ordering
(<) :: a -> a -> Bool
(<=) :: a -> a -> Bool
(>) :: a -> a -> Bool
(>=) :: a -> a -> Bool
max :: a -> a -> a
min :: a -> a -> a
{-# MINIMAL compare | (<=) #-}
-- Defined in ‘GHC.Classes’
instance Ord IHaskellSysIO.IOMode -- Defined in ‘GHC.IO.IOMode’
instance Ord IHaskellSysIO.SeekMode -- Defined in ‘GHC.IO.Device’
instance (Ord a, Ord b) => Ord (Either a b) -- Defined in ‘Data.Either’
instance Ord a => Ord [a] -- Defined in ‘GHC.Classes’
instance Ord Word -- Defined in ‘GHC.Classes’
instance Ord Ordering -- Defined in ‘GHC.Classes’
instance Ord Int -- Defined in ‘GHC.Classes’
instance Ord Float -- Defined in ‘GHC.Classes’
instance Ord Double -- Defined in ‘GHC.Classes’
instance Ord Char -- Defined in ‘GHC.Classes’
instance Ord Bool -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h, Ord i, Ord j, Ord k, Ord l, Ord m, Ord n, Ord o) => Ord (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h, Ord i, Ord j, Ord k, Ord l, Ord m, Ord n) => Ord (a, b, c, d, e, f, g, h, i, j, k, l, m, n) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h, Ord i, Ord j, Ord k, Ord l, Ord m) => Ord (a, b, c, d, e, f, g, h, i, j, k, l, m) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h, Ord i, Ord j, Ord k, Ord l) => Ord (a, b, c, d, e, f, g, h, i, j, k, l) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h, Ord i, Ord j, Ord k) => Ord (a, b, c, d, e, f, g, h, i, j, k) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h, Ord i, Ord j) => Ord (a, b, c, d, e, f, g, h, i, j) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h, Ord i) => Ord (a, b, c, d, e, f, g, h, i) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g, Ord h) => Ord (a, b, c, d, e, f, g, h) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g) => Ord (a, b, c, d, e, f, g) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f) => Ord (a, b, c, d, e, f) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d, Ord e) => Ord (a, b, c, d, e) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c, Ord d) => Ord (a, b, c, d) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b, Ord c) => Ord (a, b, c) -- Defined in ‘GHC.Classes’
instance (Ord a, Ord b) => Ord (a, b) -- Defined in ‘GHC.Classes’
instance Ord () -- Defined in ‘GHC.Classes’
instance Ord a => Ord (Maybe a) -- Defined in ‘GHC.Maybe’
instance Ord IHaskellTH.TypeFamilyHead -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Type -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.TyVarBndr -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.TySynEqn -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.TyLit -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Stmt -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.SourceUnpackedness -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.SourceStrictness -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Safety -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.RuleMatch -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.RuleBndr -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Role -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Range -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Pragma -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Phases -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.PatSynDir -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.PatSynArgs -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Pat -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Overlap -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.NameSpace -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Name -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.ModuleInfo -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Match -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Loc -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Lit -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Inline -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.InjectivityAnn -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Info -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Guard -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.FunDep -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Foreign -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.FixityDirection -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Fixity -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.FamilyResultSig -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Exp -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.DerivStrategy -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.DerivClause -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.DecidedStrictness -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Dec -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Con -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Clause -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Callconv -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Body -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.Bang -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.AnnTarget -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellTH.AnnLookup -- Defined in ‘Language.Haskell.TH.Syntax’
instance Ord IHaskellSysIO.NewlineMode -- Defined in ‘GHC.IO.Handle.Types’
instance Ord IHaskellSysIO.Newline -- Defined in ‘GHC.IO.Handle.Types’
instance Ord IHaskellSysIO.BufferMode -- Defined in ‘GHC.IO.Handle.Types’
instance Ord Integer -- Defined in ‘integer-gmp-1.0.3.0:GHC.Integer.Type’

La commande :i permet également de savoir, pour un type explicite donné, de quelles classes il est une instance.

In [73]:
:i Int
type Int :: *
data Int = GHC.Types.I# GHC.Prim.Int#
-- Defined in ‘GHC.Types’
instance Enum Int -- Defined in ‘GHC.Enum’
instance Show Int -- Defined in ‘GHC.Show’
instance Eq Int -- Defined in ‘GHC.Classes’
instance Ord Int -- Defined in ‘GHC.Classes’
instance Read Int -- Defined in ‘GHC.Read’
instance Bounded Int -- Defined in ‘GHC.Enum’
instance Integral Int -- Defined in ‘GHC.Real’
instance Num Int -- Defined in ‘GHC.Num’
instance Real Int -- Defined in ‘GHC.Real’

Les principales contraintes de type, leurs dépendances et les types explicites qui les implémentent.¶

drawing
In [26]:
-- quel est le type de la fonction sqrt ?
:t sqrt
sqrt :: forall a. Floating a => a -> a

Ici, le type signifie : pour n'importe quel type de flottant (on a vu Float et Double, par exemple) que l'on nomme a, la fonction sqrt prend en paramètre une valeur de type a et renvoie une valeur de type a.

In [132]:
-- quel est le type de la fonction even ?
:t even
even :: forall a. Integral a => a -> Bool
In [133]:
-- quel est le type de la fonction (^) ?
:t (^)
(^) :: forall b a. (Integral b, Num a) => a -> b -> a
In [135]:
3 ^ 4
81
In [136]:
3.4 ^ 5
454.3542399999999
In [137]:
3 ^ 4.5
<interactive>:1:1: error:
    • Could not deduce (Integral b0) arising from a use of ‘^’
      from the context: Num a bound by the inferred type of it :: Num a => a at <interactive>:1:1-7
      The type variable ‘b0’ is ambiguous
      These potential instances exist:
        instance Integral Integer -- Defined in ‘GHC.Real’
        instance Integral Int -- Defined in ‘GHC.Real’
        instance Integral Word -- Defined in ‘GHC.Real’
        ...plus 58 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: 3 ^ 4.5
      In an equation for ‘it’: it = 3 ^ 4.5
<interactive>:1:5: error:
    • Could not deduce (Fractional b0) arising from the literal ‘4.5’
      from the context: Num a bound by the inferred type of it :: Num a => a at <interactive>:1:1-7
      The type variable ‘b0’ is ambiguous
      These potential instances exist:
        instance Fractional Double -- Defined in ‘GHC.Float’
        instance Fractional Float -- Defined in ‘GHC.Float’
        ...plus 14 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘(^)’, namely ‘4.5’
      In the expression: 3 ^ 4.5
      In an equation for ‘it’: it = 3 ^ 4.5
In [138]:
3 ^ (-4)
Negative exponent

Documentation de la fonction :

(^) :: (Num a, Integral b) => a -> b -> a 
raise a number to a non-negative integral power

⚠ Le fait de ne pas pouvoir passer un paramètre négatif n'est pas une contrainte de type. Les classes de type définissent un ensemble de fonctions qui doivent être implémentées, pas des propriétés.

Exemple de variations sur le typage¶

In [144]:
fac :: Int -> Int
fac n = product [1..n]
In [145]:
fac 10
3628800
In [146]:
fac 30
-8764578968847253504
In [147]:
fac2 :: Integer -> Integer
fac2 n = product [1..n]
In [148]:
fac2 30
265252859812191058636308480000000
In [149]:
:t fac2
fac2 :: Integer -> Integer
In [150]:
fac3 :: Int -> Integer
fac3 n = product [1..fromIntegral n]
In [151]:
fac3 30
265252859812191058636308480000000
In [152]:
fac4 n = product [1..n]
In [153]:
fac4 30
265252859812191058636308480000000
In [154]:
:t fac4
fac4 :: forall a. (Num a, Enum a) => a -> a
In [155]:
fac5 0 = 1
fac5 n = n * fac5 (n-1)
In [156]:
fac5 30
265252859812191058636308480000000
In [157]:
:t fac5
fac5 :: forall p. (Eq p, Num p) => p -> p

Éléments de correction du TP¶

In [22]:

In [23]: