Skip to content

Varianttypes

Bart Jacobs edited this page Feb 16, 2018 · 7 revisions

Varianttypes

Seizoenen

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.

Tennisscores

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 functie plus_punt_serveerder te hergebruiken, door functies andere_speler en omgekeerde_stand te definiëren.

Recursieve varianttypes

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)

Uitdrukkingen

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 tot 45.

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 van tekst_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.
Clone this wiki locally