Comprendre Go en 5 minutes, en Haskell
Voir aussi : vidéo youtube - vidéo peertube - journal linuxfr - english version
D’après leur réputation, Go et Haskell sont des langages de programmation assez opposés : Go privilégie la simplicité, Haskell l’expressivité. Cependant ces deux langages ne sont pas si éloignés que cela. Plus exactement, les concepts de base de Go se retrouvent, de façon assez ressemblante, en Haskell.
Ce tutoriel reprend, en Haskell, les exemples de code en Go de l’article Comprendre Go en 5 minutes. L’objectif n’est pas de présenter exhaustivement Go ou Haskell, ni de démontrer que l’un est “meilleur” que l’autre mais plutôt de montrer l’équivalent en Haskell de quelques fonctionnalités de Go.
Hello world
Commençons par le traditionnel “helloworld”. En Go, il faut définir un package,
importer le module fmt
et définir une fonction main
.
package main
import "fmt"
func main() {
.Println("hello world")
fmt}
Ou plus simplement :
package main
func main() {
println("hello world")
}
En Haskell, il faut également définir une fonction main
mais il n’est pas
nécessaire de définir un module ni d’importer de module particulier.
main :: IO ()
= putStrLn "hello world" main
Fonctions
En Go, la définition et l’évaluation de fonction ressemble à n’importe quel langage de type “langage C”.
package main
import "fmt"
func add(x int, y int) int { // définit une fonction add
return x + y
}
func main() {
var i, j int = 10, 2
.Println(add(i, j)) // évalue add
fmt}
En Haskell, on utilise la forme curryfiée et sans parenthèse d’évaluation.
add :: Int -> Int -> Int -- définit une fonction add
= x + y
add x y
main :: IO ()
= do
main let i = 10
= 2
j print (add i j) -- évalue add
Go peut utiliser la forme curryfiée également (voir ce commentaire).
package main
func main() {
var add = func(a int) func(b int) int {
return func(b int) int {
return a + b
}
}
var x = 10
var y = 2
println(add(x)(y))
}
Interfaces
Go permet de définir des types et des interfaces. Par exemple, on peut définir
un type GoDeveloper
implémentant une interface Developer
.
package main
import "fmt"
type Developer interface { // définit une interface Developer
() string
Code}
type GoDeveloper struct { // définit un type GoDeveloper
}
func (g GoDeveloper ) Code() string { // implémente Developer pour GoDeveloper
return "Go code"
}
func main() {
:= GoDeveloper{}
goDeveloper .Println(goDeveloper.Code())
fmt}
Le système de type de Haskell est très évolué mais les classes de types et les types algébriques permettent d’écrire un code équivalent au code Go précédent.
class Developer a where -- définit une "interface" Developer
code :: a -> String
data GoDeveloper = GoDeveloper -- définit un type GoDeveloper
instance Developer GoDeveloper where -- implémente Developer pour GoDeveloper
= "go code"
code g
main :: IO ()
= do
main let goDeveloper = GoDeveloper
putStrLn (code goDeveloper)
Processus légers
Enfin, Go propose des processus légers, appelés “go routines” et lancés via
le mot-clé go
.
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
.Sleep(100 * time.Millisecond)
time.Println(s)
fmt}
}
func main() {
go say("world") // lance un processus léger, en parallèle
("hello")
say}
Haskell possède également des processus légers, lancés via forkIO
.
import Control.Concurrent
import Control.Monad
import System.Clock
say :: String -> IO ()
= forM_ [1 .. 5] $ \_ -> do
say s 100000
threadDelay putStrLn s
main :: IO ()
= do
main "world") -- lance un processus léger, en parallèle
forkIO (say "hello" say
Erratum. J’avais mal compris le code Go : la fonction say
attend juste
100 ms et fait un affichage. Le code donné dans la vidéo n’est pas correct.
Conclusion
Le langage Go permet de définir et d’utiliser des fonctions, des types, des interfaces et des processus légers (appelés “go routines”). Ces fonctionnalités existent également en Haskell et s’utilisent de façon assez ressemblante.