Introduction au langage Haskell

Voir aussi : vidéo peertube - vidéo youtube - dépôt git

Généralités sur haskell

Notions de bases

Quelques définitions

Prelude> 42
42
Prelude> 13.37
13.37
Prelude> "toto"
"toto"
Prelude> 21*2
42
Prelude> "hello" ++ "world"
"helloworld"
Prelude> 21*2 :: Int
42
Prelude> "toto" :: String
"toto"
Prelude> x = 12
Prelude> y = "toto" :: String
Prelude> x*2
24
Prelude> y ++ y
"totototo"

Quelques remarques

x = 42  -- ceci est un commentaire
{-
ceci est 
un commentaire
-}

Types de base

x :: Int
x = 42

y :: String
y = "toto"
x :: (Int, String)
x = (42, "toto")

y :: [Int]
y = [42, 13, 37]

Notion de fonction

-- définit une fonction "ajouter"
ajouter :: Int -> Int -> Int
ajouter x y = x + y

-- évalue la fonction "ajouter" pour les paramètres 10 et 32
x :: Int
x = ajouter 10 32
-- définit une lambda et l'évalue pour le paramètre 32
x :: Int
x = (\ n -> 10+n) 32

Définir des fonctions par décomposition

formaterParite :: Int -> String
formaterParite x = if even x then "pair" else "impair"
formaterNombre :: Int -> String
formaterNombre x = case x of
  0 -> "zero"
  1 -> "un"
  otherwise -> "plusieurs"
formaterNombre :: Int -> String
formaterNombre 0 = "zero"
formaterNombre 1 = "un"
formaterNombre _ = "plusieurs"
formaterNombre' :: Int -> String
formaterNombre' x
  | x == 0    = "zero"
  | x < 0     = "negatif"
  | otherwise = "positif"

Récursivité

factorielle :: Int -> Int
factorielle 1 = 1                        -- cas terminal
factorielle x = x * factorielle (x - 1)  -- appel récursif
factorielle :: Int -> Int
factorielle x = aux 1 x
  where aux acc 1 = acc  -- fonction auxiliaire récursive terminale
        aux acc n = aux (acc*n) (n-1)

Fonction d’ordre supérieur

ajouter :: Int -> Int -> Int
ajouter x = \ y -> x + y

-- autre façon de définir :
-- ajouter x y = x + y
ajouter42 :: Int -> Int
ajouter42 = ajouter 42  -- ici seul le paramètre "x" de la fonction "ajouter" est donné

-- autre façon de définir ajouter42 :
ajouter42 y = ajouter 42 y
fois2 x = x*2
plus1 x = x+1
fois2plus1 = plus1 . fois2

-- autre façon de définir fois2plus1 :
-- fois2plus1 x = plus1 (fois2 x)
fois2plus1 x = plus1 (fois2 x)  -- calcul sur un point "x" du domaine
fois2plus1 = plus1 . fois2      -- notation point-free

ajouter42 y = ajouter 42 y  -- calcul sur un point "y"
ajouter42 = ajouter 42      -- notation point-free

Fonctions sur des listes

Prelude> 42:[13,37]
[42,13,37]
doubler :: [Int] -> [Int]
doubler [] = []
doubler (x:xs) = (2*x):(doubler xs)
doubler :: [Int] -> [Int]
doubler = map (\ x -> x*2)

-- encore plus concis :
-- doubler = map (*2)
pairs :: [Int] -> [Int]
pairs = filter (\ x -> even x)

-- encore plus concis :
-- pairs = filter even
somme :: [Int] -> Int
somme = foldl (\ acc x -> acc + x) 0

-- encore plus concis :
-- somme = foldl (+) 0

Listes en compréhension

Prelude> [(x,y) | x<-[1..10], y<-[x..10], x+y==12]
[(2,10),(3,9),(4,8),(5,7),(6,6)]

Modules

module Doubler where
doubler x = x * 2
import Doubler
x = doubler 21

Types et classes

Type algébriques

data Forme = Carre Float
           | Rectangle Float Float
monCarre = Carre 2.0
monRectangle = Rectangle 2.0 0.5
calculerSurface :: Forme -> Float
calculerSurface (Carre cote) = cote*cote
calculerSurface (Rectangle longueur largeur) = longueur*largeur
s1 = calculerSurface monCarre
s2 = calculerSurface monRectangle

Type paramétrique

renverser :: [a] -> [a]
renverser = foldl (\ acc x -> x:acc) []
l1 = renverser [1..5]
l2 = renverser "hello"

Classes de type

doubler :: Num a => a -> a
doubler x = x*2
n1 :: Int
n1 = doubler 21

n2 :: Float
n2 = doubler 1.2

Classes prédéfinies

classe fonctions de la classe types de la classe
Eq == /= Int Float String
Show show Int Float String
Num + - * negate abs signum Int Float

Instances de classe

instance Show Forme where
  show (Carre c) = "carre de côté " ++ (show c)
  show (Rectangle w h) = "rectangle de longueur " ++ (show w) ++ " et de largeur " ++ show h
main = do
  print (Carre 12)
  print (Rectangle 12 3)

Définir une nouvelle classe

class Surfacable a where
  surface :: a -> Float
instance Surfacable Forme where
  surface = calculerSurface

surfaces :: Surfacable a => [a] -> [Float]
surfaces = map surface

main = do
  print $ surfaces [Carre 12, Rectangle 12 3]

Entrées/sorties avec IO

main :: IO ()
main = print 42
main :: IO ()
main = do
  putStrLn "hello"
  print 42
main = do
  putStrLn "entrez un texte : "
  ligne <- getLine
  putStrLn ligne

Monades

renverser :: String -> IO String
renverser = return . reverse 

-- avec la notation do
main = do
  putStrLn "entrez un texte : "
  ligne <- getLine
  engil <- renverser ligne
  putStrLn engil

-- avec les opérateurs 
main = putStrLn "entrez un texte : " >> getLine >>= renverser >>= putStrLn