Paluu Haskelliin, osa 1

Kävin muutama vuosi sitten Haskell-ohjel­mointi­kurssin, jota pidin todella mielen­kiin­toisena, mutta kielen käyttö jäi sikseen – käytön jatka­miselle ei löytynyt syitä. Haluan nyt tehdä asiaan muutoksen. Suun­nitel­mani on rakentaa šakki­ohjelma, ei maailman­luokan sellainen mutta kuitenkin täysin toimiva, kaikilla säännöillä ja riittävän vahvana, jotta se osaisi minut päihittää. (Olen shakin suhteen amatööri.)

Käymäni kurssin materiaali suositteli Haskell Tool Stack -työkalua, ja aion sitä käyttää nytkin. Ehdotettu asennus­tapa *nix-järjestelmille, jossa ohjeiden mukaan haetaan skripti curlilla ja putkitetaan sh:lle, vaikuttaa hieman riskikkäältä mutta lukaistuni läpi 805-rivisen skriptin ajan sen.

curl -sSL https://get.haskellstack.org/ | sh

Testaan asennuksen pikaisesti komento­rivi­tulkilla, ajamalla stack ghci ja alla olevilla syöt­teillä. GHC on aika iso, pari­sataa mega­tavua.

Prelude> luku = 30
Prelude> luku
30
Prelude> successor = \n -> n + 1
Prelude> successor luku
31
Prelude> successor successor luku

<interactive>:5:1: error:
    • Non type-variable argument in the constraint: Num (a -> a)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall a. (Num a, Num (a -> a)) => a
Prelude> successor $ successor luku
32

Stackin dokumentaatio ehdottaa kokonaisen projekti­hakemisto­puun luontia, joka ei nyt houkuta näin pienellä projektilla, joten skippaan sen ja luon vain tiedoston Chess.hs. Asen­nukseni testaa­miseksi lisään sinne muutaman yksin­kertaisen funktion, kurssin koo­daus­harjoi­tuk­sista:

module Chess where

double :: Integer -> Integer
double n = 2 * n

factorial :: Integer -> Integer
factorial n = if n <= 0
              then 1
              else n * factorial (n - 1)

tribonacci :: Integer -> Integer
tribonacci n = tribonacci' 0 0 1 n
tribonacci' :: Integer -> Integer -> Integer -> Integer -> Integer
tribonacci' _ _ c 1 = c
tribonacci' a b c n = tribonacci' b c (a+b+c) (n-1)

Ja ajoin interak­tiivisen tulkin, jossa pääsin tätä testaamaan:

$ stack ghci Chess.hs
[...]
[1 of 1] Compiling Chess   ( /.../Chess.hs, interpreted )
Ok, one module loaded. [...]
*Chess> double 30
60
*Chess> factorial 10
3628800
*Chess> take 20 (iterate (\n -> n + 1) 1)
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
*Chess> map tribonacci $ take 15 (iterate (\n -> n + 1) 1)
[1,1,2,4,7,13,24,44,81,149,274,504,927,1705,3136,5768]

Aion projektissani käyttää vain "standardi­kirjastoa" eli Prelude-moduulia, niin pitkälti kuin mahdollista. Shakin toteutus alkaa osassa 2.