Wikifuncties:Functiemodel

From Wikifunctions
This page is a translated version of the page Wikifunctions:Function model and the translation is 88% complete.
Outdated translations are marked like this.

Wikifuncties is a meertalige catalogus van functies waaraan iedereen kan bijdragen, waar iedereen functies kan creëren, onderhouden, aanroepen en gebruiken. Elke functie kan meerdere implementaties hebben, b.v. in verschillende programmeertalen of met behulp van verschillende algoritmen. Het is een "Wikipedia van functies" en is een zusterproject gerund door de Wikimedia Foundation.

Dit document behandelt het datamodel en het evaluatiemodel van Wikifuncties.

In deze modelbeschrijving verwijzen termen met een hoofdletter naar termen die zijn gedefinieerd in het glossarium.
Het lezen van de walkthrough van een eerder prototype is zeer nuttig geweest om een betere intuïtie te krijgen van wat hier aan de hand is voordat u het volgende model leest.

Z1/ZObjecten

Wikifuncties is een wiki. Zoals bij alle wiki's wordt de inhoud van Wikifuncties voornamelijk opgeslagen op wikipagina's. Wikipagina's kunnen afzonderlijk worden bewerkt, maar toch moet het project als geheel een zekere consistentie behouden. Bovendien moeten wikipagina's afzonderlijk kunnen worden bewerkt zonder dat u alle andere pagina's hoeft te begrijpen.

We introduceren ZObjecten om de inhoud van Wikifuncties weer te geven. Elke wikipagina van de hoofdnaamruimte van Wikifuncties bevat precies één ZObject van het type Z2/Persistent object. Andere naamruimten kunnen andere inhoud bevatten, zoals beleidspagina's, gebruikerspagina's, discussiepagina's, enz. Een ZObject kan worden geserialiseerd als een JSON-object.

Een ZObject bestaat uit een lijst met sleutel/waardeparen.

  • Elke waarde in een sleutel/waarde-paar is een ZObject.
  • Waarden kunnen een Z6/Tekenreeks zijn, een Z9/Referentie zijn of een ander type hebben. Z6/Tekenreeks en Z9/Referentie worden eindwaarden genoemd. Ze breiden niet verder uit.
  • Een Z6/Tekenreeks heeft precies twee sleutels, Z1K1/type met de waarde "Z6", en Z6K1/tekenreeks -waarde, met een willekeurige tekenreeks.
  • Een Z9/Referentie heeft precies twee sleutels, Z1K1/type met de waarde "Z9" en Z9K1/referentie-ID, waarbij een tekenreeks een ZID vertegenwoordigt.
  • Elke sleutel kan slechts één keer op elk ZObject voorkomen (maar kan opnieuw voorkomen op een ingebed ZObject).

ZObjecten zijn in feite abstracte syntaxisbomen. Als er een TLDR van het project zou zijn, zou dit waarschijnlijk “zoiets als LISP in JSON” zijn. Het doel is om een gemakkelijke UX te bieden om de creatie en manipulatie van ZObjecten via een wiki-interface mogelijk te maken en zo een codeeromgeving te creëren die een groot aantal bijdragers kan bereiken om uit te groeien tot een Wikimedia-project met een actieve gemeenschap.

Elk ZObject moet een sleutel Z1K1/type hebben met een waarde die resulteert in een Z4/Type.

We gebruiken de notatie ZID/label om op een min of meer leesbare manier naar ZID's te verwijzen, waarbij ZID een ZObject-ID of een sleutel op een dergelijk object is en label is het (Engelstalige of Nederlandstalige) label dat aan die taalneutrale ID of sleutel is bevestigd.

De representatie van een ZObject die alleen wordt weergegeven als records van sleutel/waarde-paren, en die alleen eindigt in terminale knooppunten, wordt een normaalvorm genoemd. De normaalvorm van een ZObject is meestal degene die wordt gebruikt voor evaluatie.

Canonieke vorm

Om ZObjecten leesbaarder en compacter te maken, slaan we ze meestal op en verzenden we ze in de zogenaamde canonieke vorm.

Canonieke vormen gebruiken drie syntactische transformaties: voor Z9/referenties, Z6/tekenreeksen en Z881/lijsten.

Canonieke referenties

Een referentie verwijst naar een ZObject met zijn ZID. Een ZID begint met de letter Z, gevolgd door een natuurlijk getal. De normaalvorm van een referentie ziet er als volgt uit (hier en in het hele document worden ZObjecten altijd twee keer weergegeven: aan de linkerkant in de gelabelde versie, d.w.z. wanneer alle ZID's en sleutel-ID's worden vervangen door een Engels etiket, en aan de rechterkant met de ZID'en en sleutel- ID's zonder vervanging).

{
  "type": "reference",
  "reference id": "natural number"
}
{
  "Z1K1": "Z9",
  "Z9K1": "Z10"
}

De canonieke vorm vervangt dat object door een enkele tekenreeks met de ZID. De canonieke vorm van bovenstaande referentie is dus als volgt:

"natural number"
"Z10"

Merk op dat de normale en de canonieke vorm dezelfde betekenis hebben.

Canonieke tekenreeksen

Een tekenreeks is een volgorde van Unicode-codepunten, die meestal een woord of een tekst vertegenwoordigen. Het kan spaties en elk ander teken bevatten behalve de controletekens.

De normaalvorm van een Tekenreeks ziet er als volgt uit. Merk op dat de waarde van de tweede sleutel inderdaad de tekenreeks is en niet de gelabelde versie van een ZID, zoals aan de rechterzijde te zien is.

{
  "type": "string",
  "string value": "Wikifunctions"
}
{
  "Z1K1": "Z6",
  "Z6K1": "Wikifunctions"
}

Tekenreeksen kunnen meestal worden gecanoniseerd door alleen hun tekenreeksen in plaats van het hele object. De bovenstaande tekenreeks kan als volgt worden gecanoniseerd.

"Wikifunctions"
"Wikifunctions"

Merk op dat tekenreeksen die beginnen met een grote Latijnse letter en worden gevolgd door een natuurlijk getal moeten worden vermeden, omdat ze anders in conflict zouden komen met de normale weergave van een Referentie. Bijvoorbeeld, de tekenreeks "Z1" zou de volgende weergave hebben, zowel in de normale als de canonieke vorm. Want anders zou het dubbelzinnig zijn als "Z1" naar de tekenreeks Z1 zou verwijzen of een referentie naar het object met de ZID Z1.

{
  "type": "string",
  "string value": "Z1"
}
{
  "Z1K1": "Z6",
  "Z6K1": "Z1"
}

Canonieke lijsten

Lijsten worden weergegeven door de zogenaamde Benjamin Arrays. Hun beschrijving kun je hieronder vinden in de sectie Z881/Lijsten.

Representation in JSON

A ZObject can be represented in JSON using as keys the abstract ZID keys (“Z1K1”, etc.), and the JSON representation of the value.

Een beter leesbare representatie kan worden gegeven door de abstracte sleutels en ZID's te vervangen door hun labels in een bepaalde taal, de "gelabelde" representatie. The labelized version is often ambiguous and can not always be translated to the machine-readable representation.

De volgende tabel geeft een voorbeeld van een ZObject dat het natuurlijke getal 2 vertegenwoordigt. Links zien we het ZObject in het Engels, midden in het Duits en rechts het ZObject met ZID's.

{
  "type": "natural number",
  "base 10 representation": "2"
}
{
  "Typ": "natürliche Zahl",
  "Dezimaldarstellung": "2"
}
{
  "Z1K1": "Z10",
  "Z10K1": "2"
}

Zoals je kunt zien, hoeven de labels niet in het Engels te zijn, maar kunnen ze in een van de meer dan 300 talen zijn die Wikifuncties ondersteunt.

Normaalvorm

Voor de verwerking van ZObjecten door de evaluator worden alle ZObjecten omgezet in de hierboven beschreven normaalvorm. De normaalvorm is niet afhankelijk van enige implicietheid over het interpreteren van een tekenreeks waarde als een Z6/Tekenreeks of een Z9/Referentie, maar ze worden allemaal uitgedrukt als expliciete ZObjecten.

Dit betekent dat de normaalvorm van een ZObject een boom is waar alle bladeren ofwel van het type Z6/Tekenreeks of Z9/Referentie zijn.

Dit betekent ook dat alle lijsten worden weergegeven als ZObjecten, niet als arrays.

De volgende normaalvorm vertegenwoordigt het ZObject hierboven, dat de waarde van het natuurlijke getal 2 heeft.

{
  "type": {
    "type": "reference",
    "reference id": "natural number"
   },
   "base 10 representation": {
     "type": "string",
     "string value": "2"
   }
}
{
  "Z1K1": {
    "Z1K1": "Z9",
    "Z9K1": "Z10"
   },
   "Z10K1": {
     "Z1K1": "Z6",
     "Z6K1": "2"
   }
}

Normaalvormen worden gebruikt als invoer voor de evaluatie-motor. Zij zorgen ervoor dat de gegevens voor de evaluatie altijd uniform en gemakkelijk te verwerken zijn en dat er een minimaal aantal speciale situaties nodig zijn.

Persistent en vergankelijk

Elk ZObject op het hoogste niveau dat is opgeslagen op een Wikifuncties-wikipagina is een Z2/Persistent object. ZObjecten die niet op hun eigen wikipagina zijn opgeslagen, worden vergankelijke ZObjecten genoemd.

Elk persistent ZObject moet een Z2K1/id hebben, een Z6/Tekenreeks voor de ZID, wat equivalent is aan de naam van de wikipagina waar het is opgeslagen. Laten we aannemen dat er een ZObject is voor het natuurlijke getal 2 dat we eerder hebben gezien en dat dit is opgeslagen op de pagina Z702. Dit is hoe het eruit zou kunnen zien (merk op dat de driecijferige ZID's die beginnen met Z7xx slechts tijdelijke aanduidingen zijn totdat we de juiste ZID's ervoor hebben in Wikifuncties).

{
  "type": "persistent object",
  "id": {
    "type": "string",
    "string value": "Z702"
  },
  "value": {
    "type": "natural number",
    "base 10 representation": "2"
  },
  "label": {
    "type": "multilingual text",
    "texts": [
      "monolingual text",
      {
        "type": "monolingual text",
        "language": "English",
        "text": "two"
      },
      {
        "type": "monolingual text",
        "language": "German",
        "text": "zwei"
      }
    ]
  }
}
{
  "Z1K1": "Z2",
  "Z2K1": {
    "Z1K1": "Z6",
    "Z6K1": "Z702"
  },
  "Z2K2": {
    "Z1K1": "Z10",
    "Z10K1": "2"
  },
  "Z2K3": {
    "Z1K1": "Z12",
    "Z12K1": [
      "Z11",
      {
        "Z1K1": "Z11",
        "Z11K1": "Z1002",
        "Z11K2": "two"
      },
      {
        "Z1K1": "Z11",
        "Z11K1": "Z1430",
        "Z11K2": "zwei"
      }
    ]
  }
}

Alle JSON-objecten die op Wikifuncties zijn opgeslagen, worden opgeslagen in Unicode-normalisatieformulier C. Alle waarden vóór evaluatie moeten ook Unicode-genormaliseerd zijn naar Unicode-normaalvorm C.

Het Z2/Persistent object is een envelop die metagegevens levert voor het ZObject dat is ingebed in de Z2K2/waarde.

Het Z2K3/label is een ZObject van het type Z12/meertalige tekst met één Z3/Key, Z12K1/teksten, die verwijst naar een lijst met Z11/eentalige tekst-ZObjecten (onthoud dat een lijst wordt weergegeven als een array in de JSON-representatie). Het label maakt de labeling mogelijk.

Er zijn nog meer Z3/Sleutels op het Z2/Persistent object die we hier weglaten. Ze zijn allemaal gedefinieerd op het Z2/Persistent object.

Z9/Referenties

Een Z9/Referentie is een verwijzing naar de Z2K2/waarde van het ZObject met het gegeven ID en betekent dat deze Z2K2/waarde dezelfde betekenis heeft als de referentie. Als voorbeeld de volgende referentie:

"two"
"Z702"

Dit is een verkorte Z9/Referentie, die er in uitgevouwen vorm als volgt uit zou zien (zoals uitgelegd in de sectie over deserialisatie):

{
  "type": "reference",
  "reference id": "two"
}
{
  "Z1K1": "Z9",
  "Z9K1": "Z702"
}

En aangezien dit een referentie is, moet deze worden vervangen door de Z2K2/waarde van het Z2/Persistente object door de ZID Z702 (zoals hierboven vermeld), d.w.z. het zou als volgt eruit zien:

{
  "type": "natural number",
  "base 10 representation": "2"
}
{
  "Z1K1": "Z10",
  "Z10K1": "2"
}

Alle drie JSON-representaties in deze sectie hebben dezelfde betekenis voor Wikifuncties. Ze verwijzen allemaal naar het natuurlijke getal 2.

Merk op dat als een Z8/Functie een argumenttype heeft van Z2/Persistent object, dan in plaats van de Z2K2/waarde het Z2/Persistent object zelf wordt gesubstitueerd.

Z4/Types

Typen zijn ZObjecten van type Z4/Type. ZObjecten van een type worden instanties van dat type genoemd. Z702/twee hierboven was een voorbeeld van het type Z10/positief geheel getal.

A Type tells us how to interpret a value. Een type geeft ons ook de middelen om de geldigheid van een ZObject van dat type te controleren. Een type verklaart meestal de voor zijn instanties beschikbare sleutels en een functie die wordt gebruikt om de instanties te valideren.

Hier is het type voor natuurlijke getallen (vergemakkelijkt, omdat het de korte beschrijving, alias en alle behalve de eerste drie sleutels op Z4/Type overslaat).

{
  "type": "persistent object",
  "id": {
    "type": "String",
    "string value": "Z10"
  },
  "value": {
    "type": "type",
    "identity": "natural number",
    "keys": [
      "key",
      {
        "type": "key",
        "value type": "string",
        "key id": "Z10K1",
        "label": {
          "type": "multilingual text",
          "texts": [
            "monolingual text",
            {
              "type": "monolingual text",
              "language": "English",
              "text": "base 10 representation"
            },
            {
              "type": "monolingual text",
              "language": "German",
              "text": "Dezimaldarstellung"
            }
          ]
        }
      }
    ],
    "validator": "validate natural number"
  },
  "label": {
    "type": "multilingual text",
    "texts": [
      "monolingual text",
      {
        "type": "monolingual text",
        "language": "English",
        "text": "natural number"
      },
      {
        "type": "monolingual text",
        "language": "German",
        "text": "natürliche Zahl"
      }
    ]
  }
}
{
  "Z1K1": "Z2",
  "Z2K1": {
    "Z1K1": "Z6",
    "Z6K1": "Z10"
  },
  "Z2K2": {
    "Z1K1": "Z4",
    "Z4K1": "Z10070",
    "Z4K2": [
      "Z3",
      {
        "Z1K1": "Z3",
        "Z3K1": "Z6",
        "Z3K2": "Z10K1",
        "Z3K3": {
          "Z1K1": "Z12",
          "Z12K1": [
            "Z11",
            {
              "Z1K1": "Z11",
              "Z11K1": "Z1251",
              "Z11K2": "base 10 representation"
            },
            {
              "Z1K1": "Z11",
              "Z11K1": "Z1254",
              "Z11K2": "Dezimaldarstellung"
            }
          ]
        }
      }
    ],
    "Z4K3": "Z110"
  },
  "Z2K3": {
    "Z1K1": "Z12",
    "Z12K1": [
      "Z11",
      {
        "Z1K1": "Z11",
        "Z11K1": "Z1251",
        "Z11K2": "positive integer"
      },
      {
        "Z1K1": "Z11",
        "Z11K1": "Z1254",
        "Z11K2": "natürliche Zahl"
      }
    ]
  }
}

Laten we, om de kern van het Type gemakkelijker zichtbaar te maken, gewoon naar het Z4/Type kijken en de labels verwijderen:

{
  "type": "type",
  "identity": "natural number",
  "keys": [
    "key",
    {
      "type": "key",
      "value type": "string",
      "keyid": "Z10K1"
    }
  ],
  "validator": "validate natural number"
}
{
  "Z1K1": "Z4",
  "Z4K1": "Z10",
  "Z4K2": [
    "Z3",
    {
      "Z1K1": "Z3",
      "Z3K1": "Z6",
      "Z3K2": "Z10K1"
    }
  ],
  "Z4K3": "Z110"
}

Type Z10/natuurlijk getal definieert in Z4K2/sleutels de nieuwe Z10K1/base 10-representatie van de Z3/sleutel, die we hierboven hadden gebruikt in de instantie die het nummer 2 vertegenwoordigt.

Z4K3/validator wijst op een Z8/Functie die een instantie als argument neemt en een fout of de waarde zelf retourneert, in het geval er geen fout is. Indien er geen fouten worden geretourneerd is de instantie geslaagd voor de validatie. In het gegeven voorbeeld kan de Z8/Functie de volgende controles uitvoeren:

  • Er is slechts één sleutel, de Z10K1/base 10-representatie, in de instantie, naast het Z1K1/type.
  • De waarde van de base 10-representatie is van het type Z6/Tekenreeks.
  • De base 10-representatie bevat alleen cijfers.
  • De base 10-representatie begint niet met een 0, tenzij het alleen de 0 is.

Merk op dat alle deze controles worden uitgevoerd door Z8/Functies die door bijdragers worden aangelever en dat alle Typen door bijdragers kunnen worden gedefinieerd en gewijzigd. Er is niets hardcoded met betrekking tot het getaltype dat we hier gebruiken.

Een instantie kan sleutels gebruiken die niet in het Type zijn gedefinieerd. Het is aan de validatorfunctie om dat toe te staan of niet. Instanties van Z7/Functie-aanroepen gebruiken bijvoorbeeld vaak sleutels die niet zijn gedefinieerd bij Z7/Functie-aanroepen, zoals te zien is in de sectie over Z7/Functie-aanroepen. De meeste validatoren vereisen echter dat alle sleutels gedefinieerd zijn.

Maar een paar dingen zijn hardcoded, zoals het gedrag van Z7/functie-aabroep. Meer hierover later.

Z3/Sleutels

Alle sleutels moeten een K hebben gevolgd door een natuurlijk getal en worden meestal voorafgegaan door een ZID. Als ze voorafgaan aan een ZID, worden ze globale sleutels genoemd, indien niet, worden ze lokale sleutels genoemd. De volgende twee weergaven zijn bijvoorbeeld gelijkwaardig.

{
  "Z1K1": "Z7",
  "Z7K1": "Z781",
  "Z781K1": "Z702",
  "Z781K2": "Z702"
}
{
  "Z1K1": "Z7",
  "Z7K1": "Z10000",
  "K1": "Z702",
  "K2": "Z702"
}

Globale sleutels worden argumenten genoemd terwijl lokale sleutels positionele argumenten zijn.

  • De algemene regel is om globale sleutels te gebruiken wanneer het mogelijk is.
  • De belangrijkste gebruikssituatie voor lokale sleutels is wanneer een Z8/Functie of Z4/Type ter plekke wordt gemaakt en dus geen globale sleutel kan hebben omdat de aangemaakte Z8/Functie of Z4/Type zelf niet persistent is.

Een globale sleutel wordt altijd gedefinieerd op het ZObject waar het ZID-deel van de ID naar verwijst.

Z8/Functies

In de definitie van Z10/natuurlijk getal hebben we een eerste verwijzing naar een Z8/Functie gezien, Z110/validatie van een natuurlijk getal. Hier gebruiken we een veel eenvoudiger functie, Z781/optellen. Z781/optellen is een Z8/Functie die twee Z10/natuurlijke getallen neemt en een Z10/naturlijk getal teruggeeft.

We laten alleen de waarde zien.

{
 "type": "function",
 "arguments": [
   "argument declaration",
   {
     "type": "argument declaration",
     "argument type": "natural number",
     "key id": "Z781K1",
     "label": { ... }
   },
   {
     "type": "argument declaration",
     "argument type": "natural number",
     "key id": "Z781K2",
     "label": { ... }
   }
 ],
 "return type": "natural number",
 "tests": [
   "testers",
   "add one and zero",
   "add two and two"
 ],
 "implementations": [
   "implementation",
   "+ in Python",
   "recursive addition",
   "+ in JavaScript"
 ],
 "identity": "add"
}
{
 "Z1K1": "Z8",
 "Z8K1": [
   "Z17",
   {
     "Z1K1": "Z17",
     "Z17K1": "Z10",
     "Z17K2": "Z781K1",
     "Z17K3": { ... }
   },
   {
     "Z1K1": "Z17",
     "Z17K1": "Z10",
     "Z17K2": "Z781K2",
     "Z17K3": { ... }
   }
 ],
 "Z8K2": "Z10",
 "Z8K3": [
   "Z20",
   "Z711",
   "Z712"
 ],
 "Z8K4": [
   "Z14",
   "Z721",
   "Z722",
   "Z723"
 ],
 "Z8K5": "Z144"
}

Om beknopt te zijn, hebben we de Z17K3/labels verwijderd van de Z17/Argument-verklaringen, die worden geïdentificeerd met behulp van Z17K2/sleutel-ID's. Maar net als de Z3/Sleutels op Z4/Types, hebben ze labels in alle ondersteunde talen. De sleutels zijn globaal wanneer de Z8/Functie persistent is, en lokaal wanneer ze vergankelijk is.

De functie wordt gespecificeerd in de (overgeslagen) documentatie, maar ook in de Z8K3/tests en de Z8K1/type-verklaringen over de argumenten en het Z8K2/retourneer-type. Bovendien kunnen de implementaties elkaar bevestigen, omdat een functie meerdere Z8K4/Implementaties kan hebben.

Z8/Functies mogen geen bijwerkingen hebben die de status veranderen.

Z7/Functie-aanroepen

Het volgende ZObject is een functie-aanroep. In de tweede rij zien we een compacte weergave van de functie-aanroep, die een syntax gebruikt die bekend is voor functie-aanroepen.

{
  "type": "function call",
  "function": "add",
  "left": "two",
  "right": "two"
}
{
  "Z1K1": "Z7",
  "Z7K1": "Z781",
  "Z781K1": "Z702",
  "Z781K2": "Z702"
}
add(two, two) Z781(Z702, Z702)

Met behulp van literalen in plaats van persistente ZObjecten voor de argumenten, zou dit er als volgt uitzien.

  • Merk op dat we de literalen maken gebruik makend van het Z10/positief geheel getal als constructeur.
  • Alle Z4/Types kunnen zo worden genoemd, waardoor elk van hun sleutels een waarde krijgt.
  • Dit is geen Z7/Functie-aanroep, maar een notatie voor het object van het gegeven Z4/Type.
{
  "type": "function call",
  "function": "add",
  "left": {
    "type": "natural number",
    "base 10 representation": "2"
  },
  "right": {
    "type": "natural number",
    "base 10 representation": "2"
  }
}
{
  "Z1K1": "Z7",
  "Z7K1": "Z781",
  "Z781K1": {
    "Z1K1": "Z10",
    "Z10K1": "2"
  },
  "Z781K2": {
    "Z1K1": "Z10",
    "Z10K1": "2"
  }
}
add(natural number<"2">, natural number<"2">) Z781(Z10<"2">, Z10<"2">)

Wanneer deze Z7/Functie-aanroep wordt geëvalueerd, resulteert het zoals verwacht in het getal vier.

{
  "type": "natural number",
  "base 10 representation": "4"
}
{
  "Z1K1": "Z10",
  "Z10K1": "4"
}
natural number<"4"> Z10<"4">

De evaluatie wordt herhaaldelijk uitgevoerd op het evaluatieresultaat totdat een vastgesteld punt is bereikt.

Z14/Implementaties

Elke Z8/Functie kan verschillende Z14/Implementaties hebben. Er zijn drie hoofdsoorten van Z14/Implementaties: ingebouwde, Z16/code of door samenstelling van andere Z8/Functies.

Laten we eens kijken naar de functie Z781/optellen en vier verschillende Z14/implementaties voor deze functie.

Ingebouwde implementaties

Een ingebouwde implementatie vraagt de evaluator een passend evaluatieresultaat terug te geven. Built-ins zijn ingecodeerd in de evaluator. Z14K4/built-in verwijst naar de hardcoded built-in-ID (die de ZID van het Z2/Persistent object moet zijn).

{
  "type": "implementation",
  "implements": "add",
  "builtin": "Z791"
}
{
  "Z1K1": "Z14",
  "Z14K1": "Z781",
  "Z14K4": "Z791"
}

Een evaluator is zich bewust van al zijn eigen built-ins en kan ze gebruiken wanneer hij wil. Merk op dat toevoeging geen functie zou zijn die een built-in zou krijgen. Dit is hier slechts voor illustratieve doeleinden vermeld.

Z16/Code

Een implementatie in Z16/Code vertegenwoordigt een codefragment in een bepaalde programmeertaal.

{
  "type": "implementation",
  "implements": "add",
  "code": {
    "type": "code",
    "language": "javascript",
    "source": "function add(left, right) {
                 return left + right;
               }"
  }
}
{
  "Z1K1": "Z14",
  "Z14K1": "Z781",
  "Z14K3": {
    "Z1K1": "Z16",
    "Z16K1": "Z600",
    "Z16K2": "function Z781(Z781K1, Z781K2) {
                return Z781K1 + Z781K2;
              }"
  }
}
{
  "type": "implementation",
  "implements": "add",
  "code": {
    "type": "code",
    "language": "python",
    "source": "def add(left, right):
                 return left + right"
  }
}
{
  "Z1K1": "Z14",
  "Z14K1": "Z781",
  "Z14K3": {
    "Z1K1": "Z16",
    "Z16K1": "Z610",
    "Z16K2": "def Z781(Z781K1, Z781K2):
                return Z781K1 + Z781K2"
  }
}

De evaluator zou weten hoe de gegeven ZObjecten, die de argumenten vertegenwoordigen, in de ondersteunde programmeertaal te transformeren, hoe het verstrekte codefragment uit te voeren en vervolgens het resultaat terug te transformeren in een ZObject die het resultaat vertegenwoordigt.

Uiteindelijk zou de vertaling van ZObjecten naar de oorspronkelijke waarden van de ondersteunde programmeertalen binnen Wikifuncties zelf worden afgehandeld (waarvoor een nieuw ontwerpdocument nodig is). Tot dan ondersteunen we alleen Z16/Code voor argumenten en retourtypen die hardgecodeerde ondersteuning door de evaluator hebben.

Z46/Deserialisator

Een Z46/Deserialisator neemt een ZObject van een specifiek type en verandert het in een waarde voor een bepaalde programmeertaal.

Bijvoorbeeld, de volgende Z46/Deserialisatoren neemt een ZObject van type Z10/Natuurlijk getal en verandert het in een JavaScript BigInt-waarde.

{
  "type": "deserializer",
  "identity": "to BigInt",
  "type": "Natural number"
  "converter": {
    "type": "code",
    "language": "javascript",
    "source": "function deserialize( value ) {
	   return BigInt( value.decimal_representation.string_value );
     }"
  },
  "native type": "BigInt"
}
{
  "Z1K1": "Z46",
  "Z46K1": "Z787",
  "Z46K2": "Z10",
  "Z46K3": {
    "Z1K1": "Z16",
    "Z16K1": "Z600",
    "Z16K2": "function Z787(Z787K1) {
       return BigInt( Z787K1.Z10K1.Z6K1 );
     }"
  },
  "Z46K4": "BigInt"
}

Het Z46K4/native type zegt in welk type de deserialisator zal resulteren. Hierdoor kunnen we natuurlijke implementaties zoals hierboven gebruiken in een optelling.

Z64/Serialisator

De omgekeerde werking van een Z46/Deserialisator is de Z64/Serialisator. A Z64/Serialisator neemt een waarde in de gegeven programmeertaal en maakt van deze een ZObject van het gevraagde type.

{
  "type": "serializer",
  "identity": "from BigInt",
  "type": "Natural number"
  "converter": {
    "type": "code",
    "language": "javascript",
    "source": "function serialize( value ) {
	   return {
         'type': {
           'type': 'reference',
           'reference id': 'natural number'
         },
         'base 10 representation': {
           'type': 'string',
           'string value': value.toString()
         }
       }
     }"
  },
  "native type": "BigInt"
}
{
  "Z1K1": "Z64",
  "Z64K1": "Z789",
  "Z64K2": "Z10",
  "Z64K3": {
    "Z1K1": "Z16",
    "Z16K1": "Z600",
    "Z16K2": "function Z789(Z789K1) {
	   return {
         'Z1K1': {
           'Z1K1': 'Z9',
           'Z9K1': 'Z10'
         },
         'Z10K1': {
           'Z1K1': 'Z6',
           'Z6K1': Z789K1.toString()
         }
       }
     }"
  },
  "Z64K4": "BigInt"
}

Compositie

De meest draagbare (maar vaak ook de langzaamste) Z14/Implementatie wordt bereikt door de samenstelling van andere Z8/Functies.

We tonen zowel het ZObject van de implementatie, als een gemakkelijker te lezen notatie op basis van de syntax van de functie-aanroep.

{
 "type": "implementation",
 "implements": "add",
 "composition": {
   "type": "function call",
   "function": "if",
   "condition": {
     "type": "function call",
     "function": "is zero",
     "arg": {
       "type": "argument reference",
       "reference": "right"
     }
   },
   "consequent": {
     "type": "argument reference",
     "reference": "left"
   },
   "alternative": {
     "type": "function call",
     "function": "add",
     "left": {
       "type": "function call",
       "function": "successor",
       "arg": {
         "type": "argument reference",
         "reference": "left"
       }
     },
     "right": {
       "type": "function call",
       "function": "predecessor",
       "arg": {
         "type": "argument reference",
         "reference": "right"
       }
     }
   }
 }
}
{
 "Z1K1": "Z14",
 "Z14K1": "Z781",
 "Z14K2": {
   "Z1K1": "Z7",
   "Z7K1": "Z802",
   "Z802K1": {
     "Z1K1": "Z7",
     "Z7K1": "Z782",
     "Z782K1": {
       "Z1K1": "Z18",
       "Z18K1": "Z781K2"
     }
   },
   "Z802K2": {
     "Z1K1": "Z18",
     "Z18K1": "Z781K1"
   },
   "Z802K3": {
     "Z1K1": "Z7",
     "Z7K1": "Z781",
     "Z781K1": {
       "Z1K1": "Z7",
       "Z7K1": "Z783",
       "Z783K1": {
         "Z1K1": "Z18",
         "Z18K1": "Z781K1"
       }
     },
     "Z781K2": {
       "Z1K1": "Z7",
       "Z7K1": "Z784",
       "Z784K1": {
         "Z1K1": "Z18",
         "Z18K1": "Z781K2"
       }
     }
   }
 }
}
if(
  is zero(right),
  left,
  add(
    successor(left),
    predecessor(right)
  )
)
Z802(
  Z782(Z781K2),
  Z781K1,
  Z781(
    Z783(Z781K1),
    Z784(Z781K2)
  )
)

Deze samenstelling is gebaseerd op een aantal andere Z8/Functies: Z782/is nul, Z783/opvolger, Z784/voorganger, Z801/if, en het meest interessante - zichzelf. Het is volkomen oké voor een Z14//Implementatie om haar eigen Z8/Functie recursief te noemen. Merk echter op dat de evaluator de Z14/Implementatie niet recursief hoeft te noemen - een evaluator is vrij om elke implementatie bij elke terugkerende stap te kiezen.

Dit is allesbehalve snel – maar het stelt ons in staat een goed begrepen formalisatie en een zeer eenvoudige implementatie ervan te gebruiken om ervoor te zorgen dat de andere implementaties van Z781/optellen correct zijn – weliswaar waarschijnlijk van minder belang voor optelling, maar we ons voorstellen dat er Z8/Functies zijn die duidelijk meer correctere implementaties hebben en veel slimmere snellere implementaties. Wikifuncties kunnen deze implementaties met elkaar vergelijken en ons zo een gevoel van zekerheid geven over hun juistheid.

Evaluatievoorbeeld

In het volgende evalueren we de bovenstaande samenstelling. We beginnen met de volgende Z7/functie-aanroep (we houden ons alleen aan de functionele syntax vanwege de korte tijd).

add(Natural number<"2">, Natural number<"2">)
Z781(Z10<"2">, Z10<"2">)

We vervangen de functie-aanroep met de bovenstaande samenstelling en vervangen de argumenten met de gegeven waarden. Dat resulteert in de volgende code.

if(
  is zero(Natural number<"2">),
  Natural number<"2">,
  add(
    successor(Natural number<"2">),
    predecessor(Natural number<"2">)
  )
)
Z802(
  Z782(Z10<"2">),
  Z10<"2">,
  Z781(
    Z783(Z10<"2">),
    Z784(Z10<"2">)
  )
)

We evalueren de Z782/is zero(Z10/Natural number<"2">) naar de Z40/Booleaanse waarde van Z42/onwaar (aangezien 2 niet nul is). Dat resulteert in:

if(
  false,
  Natural number<"2">,
  add(
    successor(Natural number<"2">),
    predecessor(Natural number<"2">)
  )
)
Z802(
  Z42,
  Z10<"2">,
  Z781(
    Z783(Z10<"2">),
    Z784(Z10<"2">)
  )
)

Dit stelt ons in staat om de aanroep naar Z802/if te vervangen door het Z802K3/alternatief, aangezien de Z803K1/conditie onwaar is. Dat resulteert in:

add(
  successor(Natural number<"2">),
  predecessor(Natural number<"2">)
)
Z781(
  Z783(Z10<"2">),
  Z784(Z10<"2">)
)

De Z783/opvolger-functie voegt slechts één toe aan een getal en de Z784/voorganger-functie verwijdert één. Deze functies kunnen wel/niet in code of op een andere manier worden uitgevoerd, dit maakt niet echt uit. Als we beide functie-aanroepen vervangen, komen we tot de volgende aanroep:

add(
  Natural number<"3">,
  Natural number<"1">
)
Z781(
  Z10<"3">,
  Z10<"1">
)

We vervangen de aanroep Z781/optellen opnieuw met de samenstelling ervan en vervangen de argumenten met de nieuwe waarden. Dat resulteert in:

if(
  is zero(Natural number<"1">),
  Natural number<"3">,
  add(
    successor(Natural number<"3">),
    predecessor(Natural number<"1">)
  )
)
Z802(
  Z782(Z10<"1">),
  Z10<"3">,
  Z781(
    Z783(Z10<"3">),
    Z784(Z10<"1">)
  )
)

We controleren opnieuw of de waarde gegeven aan Z782/nul is (dat het is niet, het is één). We vervangen de aanroep naar Z782/is nul weer met Z42/onwaar.

if(
  false,
  Natural number<"3">,
  add(
    successor(Natural number<"3">),
    predecessor(Natural number<"1">)
  )
)
Z802(
  Z42,
  Z10<"3">,
  Z781(
    Z783(Z10<"3">),
    Z784(Z10<"1">)
  )
)

Aangezien de Z802K1/conditie opnieuw onwaar is, vervangen we de aanroep door Z802/if met het Z803K3/alternatief.

add(
  successor(Natural number<"3">),
  predecessor(Natural number<"1">)
)
Z781(
  Z783(Z10<"3">),
  Z784(Z10<"1">)
)

We vervangen de functie-aanroepen naar Z783/opvolger en Z784/voorganger met de respectieve resultaten, een nummer meer, een nummer minder.

add(
  Natural number<"4">,
  Natural number<"0">
)
Z781(
  Z10<"4">,
  Z10<"0">
)

Wij zijn nu weer op het punt om de aanroep tot Z781/optellen te vervangen door de samenstelling ervan. Dat resulteert in:

if(
  is zero(Natural number<"0">),
  Natural number<"4">,
  add(
    successor(Natural number<"4">),
    predecessor(Natural number<"0">)
  )
)
Z802(
  Z782(Z10<"0">),
  Z10<"4">,
  Z781(
    Z783(Z10<"4">),
    Z784(Z10<"0">)
  )
)

Het aanroepen naar Z782/is nul heeft nu het argument Z10/natuurlijk getal<"0"> dat inderdaad nul is. Dus de aanroep naar Z782 is nul resulteert in een Z41/waar. Dat resulteert in:

if(
  true,
  Natural number<"4">,
  add(
    successor(Natural number<"4">),
    predecessor(Natural number<"0">)
  )
)
Z802(
  Z41,
  Z10<"4">,
  Z781(
    Z783(Z10<"4">),
    Z784(Z10<"0">)
  )
)

De Z802/if-functie-aanroep heeft nu een Z41/waar Z802K1/conditie, wat betekent dat we de hele aanroep vervangen door de Z802 K2/consequentie, niet het Z803K3/alternatief. Dat resulteert in:

Natural number<"4">
Z10<"4">

Dit is een vast punt, d.w.z. het verandert niet bij evaluatie en is dus het resultaat van onze functie-aanroep.

2 en 2 is 4.

Evaluatievolgorde

De evaluatievolgorde is aan de evaluator. Aangezien alle Z8/Functies geen bijwerkingen mogen hebben, zal dit altijd tot hetzelfde resultaat leiden. Maar een onwijze evaluatiestrategie kan leiden tot veel meer rekeningen dan nodig of zelfs tot de situatie dat de evaluator niet kan te afronden. Z722/recursieve optelling geeft ons een voorbeeld dat in een eindeloze lus kan eindigen als we een volledige evaluatievolgorde proberen:

Voor de aanroep naar Z802/if in Z722/recursieve optelling zou het onwijs zijn om eerst alle drie de argumenten te evalueren en vervolgens het tweede of het derde argument terug te geven. Afhankelijk van de eerste Z802K1/voorwaarde van het argument zullen we alleen Z802K2/consequent of Z802K3/alternatief moeten retourneren. Het is nooit zo dat we zowel het tweede als het derde argument moeten evalueren.

In feite kunnen we zelfs het tweede of derde argument niet ongeëvalueerd retourneren. Onthoud dat de evaluator elk resultaat toch opnieuw zal evalueren totdat een vast punt is bereikt. Dus Z802/if kan eenvoudig worden geïmplementeerd, laat de irrelevante tak liggen en retourneert de relevante tak als een ongeëvalueerd ZObject.

Een luie evaluatiestrategie wordt over het algemeen aanbevolen, maar bijvoorbeeld wanneer de evaluator een Z16/Code-gebaseerde implementatie wil gebruiken, is dit mogelijk niet haalbaar. En dan kan de evaluator beslissen om eerst de argumenten te evalueren en dan de externe aanroep. Uiteindelijk zijn er mogelijkheden om te experimenteren met verschillende evaluatiestrategieën.

Z20/Tests

Z20/Tests zijn ZObjecten die een Z20K2/aanroep doen en vervolgens een Z20K3/validator gebruiken op het resultaat. Z20K3/Validator is een onvolledige Z7/functie-aanroep die het resultaat van de Z20K2/aanroep als eerste argument krijgt geïnjecteerd. Als de Z20K3/validator een Z41/waar geeft, slaagt de Z20/Tester, anders mislukt deze.

Tests worden gebruikt om ervoor te zorgen dat alle Z14/implementaties zich op hun juiste manier gedragen en moeten worden beschouwd als vergelijkbaar met eenheidstesten. Een Z8/Functie moet alle Z20/Tests vermelden die moeten worden goedgekeurd voor een Z14/Implementatie om meewerkend te zijn. Bovendien kunnen de verschillende Z14/Implementaties op elkaar worden getest om consistentie te waarborgen.

{
 "type": "tester",
 "function": "add",
 "call": {
   "type": "function call",
   "function": "add",
   "left": "two",
   "right": "two"
 },
 "result validator": {
   "type": "function call",
   "function": "equivalent natural number",
   "right": "four"
 }
}
{
 "Z1K1": "Z20",
 "Z20K1": "Z781",
 "Z20K2": {
   "Z1K1": "Z7",
   "Z7K1": "Z781",
   "Z781K1": "Z702",
   "Z781K2": "Z702"
 },
 "Z20K3": {
   "Z1K1": "Z7",
   "Z7K1": "Z788",
   "Z788K2": "Z704"
 }
}

In dit geval evalueren we eerst de Z20K2/aanroep, die Z781/optellen(Z702/twee, Z702/twee) is, resulterend in Z10/Natuurlijk getal<"4">. Dat wordt vervolgens gebruikt in de Z20K3/resultatenvalidator, waar het als eerste argument wordt geïnjecteerd, wat resulteert in Z788/natural number equality(Z10/Natural number<"4">, Z704/four). Deze aanroep moet resulteren in Z41/waar en dus zou de Z20/Tester moeten slagen.

Generieke types

Een generiek type wordt gerealiseerd door een Z7/Functie-aanroep naar een Z8/Functie die enkele argumenten neemt en een Z4/Type teruggeeft.

Het Z882/getypt paar is bijvoorbeeld een functie die twee Z4/Types als argumenten gebruikt, één voor het eerste en één voor het tweede element, en retourneert een inline Z4/Type. Dus om een paar Z10/Natuurlijke getallen te maken, noemen we Z882/Getypt paar(Z10/Natuurlijk getal, Z10/Natuurlijk getal) en het resultaat is een Z4/Type dat we kunnen gebruiken voor de Z1K1-veld van een ZObject.

{
 "type": {
   "type": "function call",
   "function": "typed pair",
   "first": "natural number",
   "second": "natural number"
 },
 "first": "one",
 "second": "two"
}
{
 "Z1K1": {
   "Z1K1": "Z7",
   "Z7K1": "Z882",
   "Z882K1": "Z10",
   "Z882K2": "Z10"
 },
 "K1": "Z701",
 "K2": "Z702"
}

Het resultaat van de Z7/Functie-aanroep is een dynamisch gecreëerd Z4/Type dat ervoor zorgt dat de twee elementen van het paar de juiste Z4/Typen hebben. Het resultaat van die Z7/Functie-aanroep ziet er als volgt uit.

{
 "type": "type",
 "identity": {
   "type": "function call",
   "function": "typed pair",
   "first": "natural number",
   "second": "natural number"
 },
 "keys": [
   "key",
   {
     "type": "key",
     "id": "K1",
     "value type": "natural number"
   },
   {
     "type": "key",
     "id": "K2",
     "value type": "natural number"
   }
 ],
 "validator": "validate typed pair"
}
{
 "Z1K1": "Z4",
 "Z4K1": {
   "Z1K1": "Z7",
   "Z7K1": "Z882",
   "Z882K1": "Z10",
   "Z882K2": "Z10"
 },
 "Z4K2": [
   "Z3",
   {
     "Z1K1": "Z3",
     "Z1K2": "K1",
     "Z3K1": "Z10"
   },
   {
     "Z1K1": "Z3",
     "Z1K2": "K2",
     "Z3K1": "Z10"
   }
 ],
 "Z4K3": "Z892"
}

Dit is ook een voorbeeld van het gebruik van het Z4K1/identiteitsveld op Z4/Type: het beschrijft hoe het Z4/Type is gemaakt en stelt ons in staat toegang te krijgen tot de argumenten die worden gebruikt voor het maken van een Type. Het bewaren van deze informatie in een verklaring is zeer nuttig voor de statische validatie van een functie-aanroep en voor het vergelijken van typen.

Als we een Z882/Getypt paar willen dat het Z4/Type van een of beide elementen niet beperkt, zou men de Z882/Getypt paarfunctie kunnen aanroepen met Z1/ZObject als een of beide argumenten.

Z881/Lijsten

Hier is een lijst met twee tekenreeksen.

[
 "string",
 "a",
 "b"
]
[
 "Z6",
 "a",
 "b"
]

Als we dit omzetten in ZObjecten, ziet het er als volgt uit.

{
 "type": {
   "type": "function call",
   "function": "typed list",
   "elementtype": "string"
 },
 "head": "a",
 "tail": {
   "type": {
     "type": "function call",
     "function": "typed list",
     "elementtype": "string"
   },
   "head": "b"
 }
}
{
 "Z1K1": {
   "Z1K1": "Z7",
   "Z7K1": "Z881",
   "Z881K1": "Z6"
 },
 "K1": "a",
 "K2": {
   "Z1K1": {
     "Z1K1": "Z7",
     "Z7K1": "Z881",
     "Z10K1": "Z6"
   },
   "K1": "b"
 }
}

Een JSON-array begint altijd met het type dat wordt gebruikt voor de Z881/Getypte lijst. Dit is niet het eerste element van de lijst, maar alleen het type voor de getypte lijst. Deze arrays worden Benjamin-arrays genoemd. Als we een ongetypeerde lijst willen, gebruiken we Z1/Object als argument. Een ongetypeerde lege lijst zou als eruit zien.

[
 "object"
]
[
 "Z1"
]

Z22/Evaluation result

A Z7/Function call executed in Wikifunctions always returns an object of type Z22/Evaluation result.

An Evaluation result object always contains the value returned from the execution of a Function Call and a collection of metadata gathered during the evaluation. Here's an example of a successful response:

{
    "type": "evaluation result",
    "result": "Hello, World!",
    "metadata": {
        "type": {
            "type": "function call",
            "function": "typed map",
            "key type": "string",
            "value type": "object"
        },
        "map": [
            {
                "type": "function call",
                "function": "typed pair",
                "first type": "string",
                "second type": "object"
            },
            {
                "type": {
                    "type": "function call",
                    "function": "typed pair",
                    "first type": "string",
                    "second type": "object"
                },
                "key": "orchestrationDuration",
                "value": "139 ms"
            }
        ]
    }
}
{
    "Z1K1": "Z22",
    "Z22K1": "Hello, World!",
    "Z22K2": {
        "Z1K1": {
            "Z1K1": "Z7",
            "Z7K1": "Z883",
            "Z883K1": "Z6",
            "Z883K2": "Z1"
        },
        "K1": [
            {
                "Z1K1": "Z7",
                "Z7K1": "Z882",
                "Z882K1": "Z6",
                "Z882K2": "Z1"
            },
            {
                "Z1K1": {
                    "Z1K1": "Z7",
                    "Z7K1": "Z882",
                    "Z882K1": "Z6",
                    "Z882K2": "Z1"
                },
                "K1": "orchestrationDuration",
                "K2": "139 ms"
            }
        ]
    }
}

If the evaluation is unsuccessful, the response field will contain Z24/Void, while the metadata field will contain an "error" key with the details of the failure. This is an example of a failed Evaluation result object:

{
    "type": "evaluation result",
    "result": "void",
    "metadata": {
        "type": {
            "type": "function call",
            "function": "typed map",
            "key type": "string",
            "value type": "object"
        },
        "map": [
            {
                "type": "function call",
                "function": "typed pair",
                "first type": "string",
                "second type": "object"
            },
            {
                "type": {
                    "type": "function call",
                    "function": "typed pair",
                    "first type": "string",
                    "second type": "object"
                },
                "key": "errors",
                "value": {
                    "type": "error",
                    "error type": "unspecified error",
                    "error value": {
                        "type": {
                            "type": "function call",
                            "function": "errortype to type",
                            "errortype": "unspecified error"
                        },
                        "error information": "Some error happened"
                    }
                }
            }
        ]
    }
}
{
    "Z1K1": "Z22",
    "Z22K1": "Z24",
    "Z22K2": {
        "Z1K1": {
            "Z1K1": "Z7",
            "Z7K1": "Z883",
            "Z883K1": "Z6",
            "Z883K2": "Z1"
        },
        "K1": [
            {
                "Z1K1": "Z7",
                "Z7K1": "Z882",
                "Z882K1": "Z6",
                "Z882K2": "Z1"
            },
            {
                "Z1K1": {
                    "Z1K1": "Z7",
                    "Z7K1": "Z882",
                    "Z882K1": "Z6",
                    "Z882K2": "Z1"
                },
                "K1": "errors",
                "K2": {
                    "Z1K1": "Z5",
                    "Z5K1": "Z500",
                    "Z5K2": {
                        "Z1K1": {
                            "Z1K1": "Z7",
                            "Z7K1": "Z885",
                            "Z885K1": "Z500"
                        },
                        "Z500K1": "Some error happened"
                    }
                }
            }
        ]
    }
}

These examples are just condensed versions of the real Evaluation result objects and only contain one example key in the Metadata field. In real examples, the metadata collection will return all the metrics gathered by the backend services, including the run's duration, CPU usage, and memory usage.

For a more detailed description of all the possible metadata returned in the Evaluation result object, see the Function call metadata guide in Mediawiki.

Z5/Fouten

Een Z7/Functie-aanroep kan altijd leiden tot een Z5/Fout. Dit kan voor meer of minder onherstelbare gevallen zijn (d.w.z. deling door nul of geen geheugen meer wordt beide op dezelfde manier behandeld).

Z5 is a generic type. Each instance of Z5 references the ZID of an error type (in Z5K1/error type), and that error type determines the type of Z5K2/error value, and the keys that will be present therein. Each error type is an instance of Z50/error type, and ZIDs Z500–Z599 are reserved for error types.

Additional information is available at Abstract Wikipedia/Representation of errors.

Z99/Quote

Z99/Quote is used as a wrapper around another ZObject, to indicate that it should not be evaluated ("resolved"). (This is similar to quoting in Lisp.) Z99/Quote has a single key, Z99K1/quotation, of type Z1/Object.

To illustrate, some parts of error objects (instances of Z5/Error) are quoted when they get created during the execution of a function call. For example, an error of type Z507/Error in evaluation includes a copy of the entire function call whose execution caused the error (as the value of Z507K1/function call). Because this function call is very likely to be malformed in some way, we ensure that no further attempt is made to evaluate it, by quoting it inside the error object. (Thus, the type of Z507K1 is declared as Z99, and its value is always quoted.)

We use the following guidelines for when to use Z99/Quote:

  1. Quote a ZObject when we believe it may be invalid in some way.
  2. But do not quote Z1K1 by itself. If its value is in doubt, quote the entire object that contains it.
  3. Quote resolvable keys (keys whose values contain instances of Z7, Z9, or Z18) that might inappropriately be ingested as the input to a function.
  4. Quote when resolving a value might cause a catastrophe (e.g. infinite recursion).

Note: as our resolution strategy evolves, it's possible that (3) and (4) could become unnecessary.

Niet-functionele functies

Een Z8/Functie mag geen bijwerkingen hebben. Alle Z8/Functies moeten functioneel zijn. Dat wil zeggen, zij moeten dezelfde waarde teruggeven wanneer zij met dezelfde argumenten worden aangeroepen. Dit betekent dat Z8/Functies zoals "retourneer een willekeurig getal" of "retourneer het huidige tijdstip" niet mogelijk zijn.

This might change in the future. Dit zal in een later document worden behandeld.

Zx/Somtypes

Een bijzonder nuttig generiek type is het Zx/Somtype, dat een lijst met Z4/Types gebruikt en een Z4/Type retourneert dat precies één exemplaar van elk van de gegeven typen kan bevatten.

Dit zal ook niet-vereiste parameters in functie-aanroepen mogelijk maken.

Dit zal in een later document worden behandeld.

Enkele vragen en taken om te doen

  • Hebben we ergens in het begin een “vereist/optie” nodig voor sleutels? — Nee
  • Vervang de standaardwaarden op Z3/Sleutel met Zx/Som? (Of op zijn minst in overeenstemming brengen met Z17/argumentdeclaratie)
  • Dat kan later worden gedaan als we Z3 niet standaard willen.
  • Make a note that all is Unicode and that all is the normalization required by MediaWiki
  • Rewrite intro to start with normal and then canonicalize

Zie ook