Understand Go in 5 minutes, in Haskell
See also: youtube video (french) - peertube video (french) - version française
Go and Haskell are rather opposite: Go favors simplicity, Haskell favors expressiveness. However, these two programming languages are not so different. More precisely, the basic concepts in Go are also available in Haskell, and quite similarly.
This post translates, in Haskell, the code samples presented in this article. The objective is not to detail Go and Haskell, nor to demonstrate that one is better than the other, but only to illustrate equivalent Haskell code to some Go code.
Hello world
Let’s start with a classic “helloworld”. In Go, we have to define a package, import the fmt
module and define a main
function.
package main
import "fmt"
func main() {
.Println("hello world")
fmt}
Or more simply:
package main
func main() {
println("hello world")
}
In Haskell, we also have to define a main
function, but it’s not mandatory to define a module.
main :: IO ()
= putStrLn "hello world" main
Functions
Go has functions. The syntax for defining or evaluating a function is quite similar to any C-like language.
package main
import "fmt"
func add(x int, y int) int { // define a function add
return x + y
}
func main() {
var i, j int = 10, 2
.Println(add(i, j)) // evaluate add
fmt}
In Haskell, functions are defined using the curried form. Function evaluation needs no parenthesis.
add :: Int -> Int -> Int -- define a function add
= x + y
add x y
main :: IO ()
= do
main let i = 10
= 2
j print (add i j) -- evaluate add
Go can use the curried form too (see this comment).
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 can define types and interfaces. For example, we can define a GoDeveloper
type that implements a Developer
interface.
package main
import "fmt"
type Developer interface { // define an interface Developer
() string
Code}
type GoDeveloper struct { // define a type GoDeveloper
}
func (g GoDeveloper ) Code() string { // instantiate Developer for GoDeveloper
return "Go code"
}
func main() {
:= GoDeveloper{}
goDeveloper .Println(goDeveloper.Code())
fmt}
The Haskell type system is very powerful but the previous code can be implemented quite simply, using type classes and algebraic data types.
class Developer a where -- define an "interface" Developer
code :: a -> String
data GoDeveloper = GoDeveloper -- define a type GoDeveloper
instance Developer GoDeveloper where -- instantiate Developer for GoDeveloper
= "go code"
code g
main :: IO ()
= do
main let goDeveloper = GoDeveloper
putStrLn (code goDeveloper)
Lightweight processes
Finally, Go has lightweight processes, called “go-routines”. A go-routine is basically a function called asynchronously using the keyword 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") // launch a lightweight process asynchronously
("hello")
say}
Haskell also has lightweight processes, launched using 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") -- launch a lightweight process asynchronously
forkIO (say "hello" say
Conclusion
The Go language can define and use functions, types, interfaces and lightweight processes ("go-routines). These features also exist in Haskell and can be used quite similarly.