-
Notifications
You must be signed in to change notification settings - Fork 0
Varianttypes
OCaml laat aan de programmeur toe, zelf nieuwe types te definiëren. Het belangrijkste soort types dat je in OCaml kunt definiëren heet varianttypes. Bijvoorbeeld:
type seizoen = Winter | Lente | Zomer | Herfst
Deze definitie definieert het varianttype seizoen
, alsook de vier constructoren van dit type: Winter
, Lente
, Zomer
, en Herfst
. Er zijn dus vier waarden van dit type.
Om met varianttypes te werken, kan je match
-uitdrukkingen gebruiken, net zoals voor lijsten. (Het type van lijsten in OCaml is eigenlijk gewoon een voorgedefinieerd varianttype.) Bijvoorbeeld: de volgende functie berekent de tekstvoorstelling van een seizoen:
let tekst_van_seizoen seizoen =
match seizoen with
Winter -> "winter"
| Lente -> "lente"
| Zomer -> "zomer"
| Herfst -> "herfst"
Opdracht:
- Tik
tekst_van_seizoen Winter
in. - OCaml antwoordt met
- : string = "winter"
.
Oefening:
- Definieer de functie
volgend_seizoen
die het seizoen, volgend op een gegeven seizoen, berekent.
Constructoren van een varianttype kunnen argumenten hebben. De volgende types laten bijvoorbeeld toe de stand van een spel in een tennismatch bij te houden:
type speler = Serveerder | Ontvanger
type score = Nul | Vijftien | Dertig | Veertig
type stand =
Regulier of score * score
| Voordeel of speler
| Gewonnen of speler
Hierbij stelt Regulier Vijftien Dertig
bijvoorbeeld voor dat de serveerder vijftien punten heeft, en de ontvanger dertig.
De volgende functie berekent, gegeven een stand, de nieuwe stand nadat de serveerder een rally wint:
let plus_punt_serveerder stand =
match stand with
Regulier (Nul, scoreOntvanger) -> Regulier (Vijftien, scoreOntvanger)
| Regulier (Vijftien, scoreOntvanger) -> Regulier (Dertig, scoreOntvanger)
| Regulier (Dertig, scoreOntvanger) -> Regulier (Veertig, scoreOntvanger)
| Regulier (Veertig, Veertig) -> Voordeel Serveerder
| Regulier (Veertig, scoreOntvanger) -> Gewonnen Serveerder
| Voordeel Serveerder -> Gewonnen Serveerder
| Voordeel Ontvanger -> Regulier (Veertig, Veertig)
Bijvoorbeeld: plus_punt_serveerder (Regulier (Nul, Nul))
evalueert tot Regulier (Vijftien, Nul)
.
Merk op dat de functie plus_punt_serveerder
het geval dat er al een speler gewonnen heeft, afhandelt. In dat geval gooit de functie een MatchFailure
.
Oefening:
- Definieer de functie
plus_punt_ontvanger
. Probeer hierbij de functieplus_punt_serveerder
te hergebruiken, door functiesandere_speler
enomgekeerde_stand
te definiëren.
Argumenten van een constructor van een varianttype kunnen zelf ook weer van dat varianttype zijn. We spreken dan van een recursief varianttype. Een gekend voorbeeld hiervan is het type van de lijsten. Het type van de lijsten van getallen zouden we zelf als volgt kunnen definiëren:
type getallenlijst = LegeGetallenLijst | NietLegeGetallenLijst of int * getallenlijst
let voorbeeld = NietLegeGetallenLijst (1, NietLegeGetallenLijst (2, NietLegeGetallenLijst (3, LegeGetallenLijst)))
let rec getallenlijst_aan_elkaar getallen1 getallen2 =
match getallen1 with
LegeGetallenLijst -> getallen2
| NietLegeGetallenLijst (kop, staart) -> NietLegeGetallenLijst (kop, getallenlijst_aan_elkaar staart getallen2)
Ziehier een ander voorbeeld van een recursief varianttype:
type uitdrukking =
GetalUitdrukking of int
| SomUitdrukking of uitdrukking * uitdrukking
| VerschilUitdrukking of uitdrukking * uitdrukking
| ProductUitdrukking of uitdrukking * uitdrukking
| QuotientUitdrukking of uitdrukking * uitdrukking
Dit type laat toe eenvoudige uitdrukkingen voor te stellen:
| Uitdrukking | Voorstelling als waarde van type 'uitdrukking'
+------------------+-----------------------------------------------
| 42 | GetalUitdrukking 42
| 42 + 3 | SomUitdrukking (GetalUitdrukking 42, GetalUitdrukking 3)
| 42 - 3 | VerschilUitdrukking (GetalUitdrukking 42, GetalUitdrukking 3)
| 42 - 3 - 7 | VerschilUitdrukking (VerschilUitdrukking (GetalUitdrukking 42, GetalUitdrukking 3), GetalUitdrukking 7)
| 42 - 4 * 5 | VerschilUitdrukking (GetalUitdrukking 42, ProductUitdrukking (GetalUitdrukking 4, GetalUitdrukking 5))
| (42 - 4) * 5 | ProductUitdrukking (VerschilUitdrukking (GetalUitdrukking 42, GetalUitdrukking 4), GetalUitdrukking 5)
| 12 / 3 / 2 | QuotientUitdrukking (QuotientUitdrukking (GetalUitdrukking 12, GetalUitdrukking 3), GetalUitdrukking 2)
De twee deel-uitdrukkingen van een som-, verschil-, product-, of quotiënt-uitdrukking noemen we de linker- en rechter-operand van de uitdrukking.
Oefening:
- Definieer een functie
waarde_van
die, gegeven een uitdrukking, de uitdrukking uitrekent en de waarde ervan teruggeeft. Bijvoorbeeld:waarde_van (SomUitdrukking (GetalUitdrukking 42, GetalUitdrukking 3))
evalueert tot45
.
Oefening:
- Definieer een functie
tekst_van
die een tekstvoorstelling van een uitdrukking berekent. Gebruik voldoende haakjes, zodat de betekenis van de uitdrukking behouden blijft. Het is niet erg als je teveel haakjes gebruikt. Bijvoorbeeld: een mogelijke uitkomst vantekst_van (SomUitdrukking (GetalUitdrukking 42, GetalUitdrukking 3))
is(42 + 3)
.
Laten we de getal-uitdrukkingen, de productuitdrukkingen, en de quotiëntuitdrukkingen samen de multiplicatieve uitdrukkingen noemen. Om de structuur van een gegeven uitdrukking correct als tekst weer te geven, moeten er haakjes staan rond de rechter-operand van een som- of verschil-uitdrukking of de linker-operand van een product- of quotiënt-uitdrukking indien die operand geen multiplicatieve uitdrukking is, en moeten er haakjes staan rond de rechteroperand van een product- of quotiënt-uitdrukking indien die operand geen getaluitdrukking is.
Oefening:
- Herdefinieer de functie
tekst_van
zodanig dat de uitkomst net zoveel haakjes bevat als nodig om de structuur van de gegeven uitdrukking te behouden. Het is hiervoor nuttig, hulpfuncties te definiëren.