Plus de Haskell.
This commit is contained in:
parent
50586a7a9c
commit
c907bd74da
37
HSK18.md
Normal file
37
HSK18.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Haskell 18
|
||||||
|
|
||||||
|
### Exercice 1
|
||||||
|
1. Une fonction récursive est une fonction qui s'auto-référence et qui s'appelle elle-même. C'est utilisé pour décrire des suites mathématiques récursives, ou pour traiter plus généralement des problèmes qui ont une solution inductive simple.
|
||||||
|
2.
|
||||||
|
```
|
||||||
|
allMin :: Ord a => [a] -> a
|
||||||
|
allMin [e] = e
|
||||||
|
allMin (e:s) = min e (allMin s)
|
||||||
|
```
|
||||||
|
3. Par exemple lors de l'appel `allMin [1,4,3,7,9,5,8,0,1,3,45,5]`, Haskell va chercher dans ses pattern un qui corresponde, il trouve `allMin e:s`, puis remplace par `min 1 (allMin [4,3,7,9,5,8,0,1,3,45,5])`. Il continue jusqu'à tomber sur un cas qu'il connait, ici `allMin [5]`.
|
||||||
|
|
||||||
|
### Exercice 2
|
||||||
|
1.
|
||||||
|
a. La factorielle est naturellement définie récursivement pas (n+1)! = (n+1)*n! et 0!=1
|
||||||
|
b. Cette fonction semble peu naturelle en récursif, bien que ce soit possible (c'est toujours possible), on aurait une fonction au moins aussi compliqué qu'un algo pour la multplication quelconque.
|
||||||
|
c. Naturellement définie car `replicate (n+1) x = x:(replicate n x)` et `replicate 0 x = []`
|
||||||
|
d. Naturellement définie car `sum e::s = e+(sum s)` et `sum [] = 0`
|
||||||
|
|
||||||
|
2.
|
||||||
|
```
|
||||||
|
fact :: Num a => Eq a => a -> a
|
||||||
|
fact 0 = 1
|
||||||
|
fact n = n*(fact (n-1))
|
||||||
|
|
||||||
|
replicate' :: (Num i, Ord i) => i -> a -> [a]
|
||||||
|
replicate' n x
|
||||||
|
| n <= 0 = [ ]
|
||||||
|
| otherwise = x : replicate' (n - 1) x
|
||||||
|
|
||||||
|
ssum :: Num a => [a] -> a
|
||||||
|
ssum [] = 0
|
||||||
|
ssum (e:s) = e+(ssum s)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exercice 3
|
||||||
|
Voir fstfunc.hs
|
||||||
57
HSK19.md
Normal file
57
HSK19.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Haskell 19
|
||||||
|
|
||||||
|
### Exercice 1
|
||||||
|
1. Une fonction d'ordre superieur est une fonction qui prend d'autres fonctions en entrée, ou qui renvoie une fonction. C'est ce qui fait que les langages fonctionnels sont trops biens.
|
||||||
|
2. Dans le type de telles fonctions, il devra y avoir un parenthèsages des flèches `->` car on sera dans des cas ou la précédence à gauche fait défaut. Par exemple pour une fonction `(Int -> Int) -> Float -> [Float]`.
|
||||||
|
3.
|
||||||
|
```
|
||||||
|
apply3 :: (a -> a) -> a -> a
|
||||||
|
apply3 f x = f (f (f x))
|
||||||
|
```
|
||||||
|
4. La fonction d'entrée doit être une application interne afin de pouvoir la composer avec elle même (la loi de composition implique type entrée = type sortie).
|
||||||
|
|
||||||
|
5.
|
||||||
|
```
|
||||||
|
applyN :: Int -> (a->a) -> a -> a
|
||||||
|
applyN 0 f x = x
|
||||||
|
applyN n f x = f (applyN (n-1) f x)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exercice 2
|
||||||
|
1. L'expression crée une application square qui met au carrée et renvoie la liste [1..5] à laquelle on a appliqué `square` à chaque élément.
|
||||||
|
2. La fonction `map` sert à appliquer une fonction à tous les éléments d'une liste.
|
||||||
|
3. `map` est donc de type `(a -> b) -> [a] -> [b]` car elle prend en entrée une fonction «transformant les `a` en `b`» et l'applique à une liste de `a` pour en faire une liste de `b`.
|
||||||
|
4.
|
||||||
|
```
|
||||||
|
myMap :: (a -> b) -> [a] -> [b]
|
||||||
|
myMap f l = [f x | x <- l]
|
||||||
|
```
|
||||||
|
5.
|
||||||
|
```
|
||||||
|
myMap2 :: (a->b)->[a]->[b]
|
||||||
|
myMap2 f [] = []
|
||||||
|
myMap2 f (e:s) = (f e):(myMap2 f s)
|
||||||
|
```
|
||||||
|
6. L'expression renvoie la liste `[1..10]` privée de tous ses entiers non impairs.
|
||||||
|
7. La fonction `filter` permet de filtrer les éléments d'une liste selon un prédicat, c'est à dire une application du type `a -> Bool`.
|
||||||
|
8. La fonction `filter` est du type `(a -> Bool) -> [a] -> [a]` car elle prend en entrée un prédicat sur des `a` et une liste de `a` et renvoie une liste incluse, donc de même type `a`.
|
||||||
|
9.
|
||||||
|
```
|
||||||
|
myFilter :: (a -> Bool) -> [a] -> [a]
|
||||||
|
myFilter f [] = []
|
||||||
|
myFilter f (e:s)
|
||||||
|
| f e = e:(filter f s)
|
||||||
|
| otherwise = filter f s
|
||||||
|
```
|
||||||
|
10. L'expression renvoie la liste `[(1,'a'),(2,'b'),(3,'c')]`
|
||||||
|
11. La fonction `zip` transforme un couple de listes en une liste de couples tels que la liste résultat soit de la taille de la plus petite des listes d'entrée et que le ième élément de la premiere liste soit mis en couple avec le ième de la seconde.
|
||||||
|
12. La fonction `zip` est du type `[a] -> [b] -> [(a, b)]` car elle prend deux liste de types potentiellement différents, et crée une liste de couples contenant dans l'ordre les types des listes.
|
||||||
|
13. L'expression renvoie la liste `[1+4,2+5]`.
|
||||||
|
14. La fonction zipWith colle les données de deux listes comme zip, mais applique une fonction passée en paramètre pour la fusion des données.
|
||||||
|
15. La fonction zipWith est du type `(a -> b -> c) -> [a] -> [b] -> [c]` carre la fonction paramètre prend deux paramètres, un de chaque liste (de types a priori différents) et renvoie quelque chose de type ici aussi à priori différent. Il est appliqué ensuite à une liste du type de son premier paramètre, puis à une liste du type de son second paramètre et renvoie une liste du type son type de sortie.
|
||||||
|
16.
|
||||||
|
```
|
||||||
|
myZipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
|
||||||
|
myZipWith o l l' = map applicateur (zip l l')
|
||||||
|
where applicateur (x,y) = o x y
|
||||||
|
```
|
||||||
22
HSK20.md
Normal file
22
HSK20.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Haskell 20
|
||||||
|
|
||||||
|
### Exercice 1
|
||||||
|
1. Une fonction curryfiée est une fonction qui ne prend pas le n-uplet de ses n paramètres en guise d'unique paramètre, mais décrit plutot la fonction comme une fonction du premier paramètre renvoyant une fonction des autres paramètres (inductivement).
|
||||||
|
2. Les deux résultats suivants sont compris pareil par Haskell: `max 67 5` est l'application à max de 67 puis au résultat de 5.
|
||||||
|
`max 67` est une application qui est semblable à l'identité sur les nombres superieurs à 67 et qui est constante à 67 sur les nombres inferieurs à 67.
|
||||||
|
3. `max` est du type `a -> a -> a` ce qui signifie `a -> (a -> a)`. La curryfication est visible car la fonction renvoie une fonction qui n'est pas le résultat normalement attendu par la fonction.
|
||||||
|
4. La curryfication est semblable à l'utilisation de fonction anonymes car une fonction anonyme qui dépend du contexte est une fonction globale à laquelle on a appliqué le contexte (l'application reste partielle).
|
||||||
|
|
||||||
|
### Exercice 2
|
||||||
|
1. L'expression donnée renvoie la liste des nombres de 1 à 100 privée de ceux qui n'étaient pas strictement superieurs à 10.
|
||||||
|
2. Une fonction infixe est une fonction qui s'écrit comme un opérateur, c'est à dire entouré de ses paramètres (par exemple `34 + 8` au lieu de `add 34 8`).
|
||||||
|
3. On peut transformer une fonction *infix* en fonction *prefix* en entourant l'opérateurs de parenthèses. Par exemple les expressions `53 - 11` et `(-) 53 11` sont équivalentes.
|
||||||
|
4. La section (*sectionning*) est un moyen d'appliquer partiellement des fonctions infixes sans passer par leur version préfixe.
|
||||||
|
5. On peut avoir simplement `div20 = (/20)
|
||||||
|
6. `any (>5) [1..10]`
|
||||||
|
|
||||||
|
### Exercice 3
|
||||||
|
1. L'expression renvoie la liste des nombres de 1 à 10 auxquels on a pris l'opposé.
|
||||||
|
2. Un lambda est un moyen de définir une fonction dans un *scope* réduit et sans lui donner de nom, par exemple en paramètre d'une fonction.
|
||||||
|
3. Les lambdas sont déclarés avec la sytaxe suivante: `(\x -> corps)` où `x`est le paramètre de la fonctions et `corps` est le «processus» de la fonction, là valeur retournée pouvant dépendre de `x` (c'est en général préférable).
|
||||||
|
4. `map (\(a,b) -> a*10 + (a*b) + b) (zip [1..5] [6..10])`
|
||||||
71
HSK21.md
Normal file
71
HSK21.md
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# Haskell 21
|
||||||
|
|
||||||
|
### Exercice 1
|
||||||
|
1. Une récursion terminales est une récursion telle que l'appel récursif est le dernier appel de la fonction.
|
||||||
|
2. La première fonction va calculer `10*(factorielle (10-1))` puis `10*9*(factorielle (10-2))` jusqu'à obtenir le gros produit de *n* termes `10*9*8*7*6*5*4*3*2*1`. La seconde va appeler `go 10 1` puis `go (10-1) 10` puis `go (10-2) 90` ..., et à la fin, le résultat sera déjà calculé.
|
||||||
|
C'est bien sûr la seconde qui est récursive terminale.
|
||||||
|
|
||||||
|
### Exercice 2
|
||||||
|
1.
|
||||||
|
```
|
||||||
|
minimum' :: [Float] -> Float
|
||||||
|
minimum' [e] = e
|
||||||
|
minimum' (e:s) = min e (minimum' s)
|
||||||
|
|
||||||
|
minimum'' :: [Float] -> Float
|
||||||
|
minimum'' (u:l) = go l u
|
||||||
|
where go [] x = x
|
||||||
|
go (e:s) x
|
||||||
|
| e>x = go s x
|
||||||
|
| otherwise = go s e
|
||||||
|
```
|
||||||
|
2.
|
||||||
|
```
|
||||||
|
and' :: [Bool] -> Bool
|
||||||
|
and' [] = True
|
||||||
|
and' (e:s) = e && (and' s)
|
||||||
|
|
||||||
|
and'' :: [Bool] -> Bool
|
||||||
|
and'' l = go l True
|
||||||
|
where go [] x = x
|
||||||
|
go (e:s) x = go s (e && x)
|
||||||
|
```
|
||||||
|
3.
|
||||||
|
```
|
||||||
|
reduce :: (t->t->t) -> [t] -> t
|
||||||
|
reduce f [e] = e
|
||||||
|
reduce f (e:s) = f e (reduce f s)
|
||||||
|
|
||||||
|
reduce' :: (t->t->t) -> [t] -> t
|
||||||
|
reduce' f (e:s) = go s e
|
||||||
|
where go [] x = x
|
||||||
|
go (h:t) x = go t (f h x)
|
||||||
|
```
|
||||||
|
|
||||||
|
Attentiton, si on met des fonctions non symmétriques dans reduce et reduce', elle ne fonctionneront pas pareil !
|
||||||
|
|
||||||
|
### Exercice 3
|
||||||
|
1. Si on passe la liste vide en paramètre de reduce, Haskell se plaint que la définition n'est pas complète.
|
||||||
|
2. Une fonction est dite totale losque sa définition existe et est calculable pour tout objet du type spécifié par la fonction. Exemples de foncitons totales: `(+)`, `length`. Exemple de fonctions non totales: `reduce`, `head`.
|
||||||
|
3.
|
||||||
|
```
|
||||||
|
reduceTotal :: (t->t->t) -> t -> [t] -> t
|
||||||
|
reduceTotal f x0 [] = x0
|
||||||
|
reduceTotal f x0 (e:s) = f e (reduceTotal f x0 s)
|
||||||
|
|
||||||
|
reduceTotal' :: (t->t->t) -> t -> [t] -> t
|
||||||
|
reduceTotal' f x0 l = go l x0
|
||||||
|
where go [] x = x
|
||||||
|
go (h:t) x = go t (f h x)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exercice 4
|
||||||
|
1. Dans le Prélude, et même dans le module Data.List, on trouve les fonctions suivantes:
|
||||||
|
- `foldl1` qui fonctionne comme reduce
|
||||||
|
- `foldr1` qui fonctionne comme reduce'
|
||||||
|
- `foldl` ou `foldl'` qui fonctionne comme reduceTotal
|
||||||
|
- `foldr` qui fonctionne comme reduceTotal'
|
||||||
|
|
||||||
|
2. Dans les trois cas, `foldr` profite de l'évaluation terminale, qui accélere le processus.
|
||||||
|
L'évaluation paresseuse ne fonctionne pour aucun des deux. Pour `foldr`, l'évaluation ira de toute façon au bout, et pour `foldl`, Haskell crée l'expression de l'évaluer.
|
||||||
|
3. POur éviter ce problème, il est possible d'utiliser `foldl'` qui évalue l'expression à chaque boucle de récursion. Par exemple, dans notre premier exemple de factoriel, Haskell ferait le processus suivant: `10*(factorielle (10-1))` puis `10*9*(factorielle (10-2))` puis simplification en `90*(factorielle (10-2))` puis `8*90*(factorielle (10-3))` puis `720*(factorielle (10-3))` et cætera. Alors le calcul ne prendra pas *trop* de place en mémoire.
|
||||||
Loading…
x
Reference in New Issue
Block a user