Jump to content

Wikifunctions:Modèle de fonctions

From Wikifunctions
This page is a translated version of the page Wikifunctions:Function model and the translation is 100% complete.
Outdated translations are marked like this.
Documentation technique de Wikifunctions
Présentations générales
Fonctionnalités pour l'utilisateur
Spécifique aux serveurs

Wikifonctions (Wikifunctions en anglais) est un catalogue multilingue de fonctions auquel chacun peut contribuer, créer, maintenir, appeler et utiliser les fonctions. Chaque fonction peut avoir plusieurs mises en œuvre, par exemple dans des langages de programmation différents ou en utilisant des algorithmes différents. C’est une « Wikipédia de fonctions » et un projet frère soutenu et conduit par la Fondation Wikimédia.

Ce document couvre le modèle de données et le modèle d’évaluation de Wikifonctions.

Tout au long de cette description de modèle, les termes capitalisés se réfèrent à des termes définis dans le glossaire.
La lecture de la procédure pas à pas d’un précédent prototype a été très utile pour obtenir une meilleure intuition de ce qui s’y passe avant de lire le modèle suivant.

Z1/Z-Objets (ZObjects)

Wikifonctions est un wiki. Comme dans tous les wikis, le contenu de Wikifonctions est principalement stocké dans des pages wiki. Les pages wiki peuvent être modifiées individuellement et pourtant le projet dans son entier doit conserver une certaine consistance. Aussi les pages doivent être individuellement modifiables sans avoir à comprendre toutes les autres pages.

Nous introduisons les Z-Objets pour représenter le contenu de Wikifonctions. Chaque page wiki de l’espace de noms principal de Wikifonctions contient exactement un Z-Objet, de type Persistent object (Z2). D’autres espaces de noms peuvent contenir d’autres contenus, comme les pages de politique, les pages d’utilisateurs, les pages de discussion, etc. Un Z-Objet peut être sérialisé sous forme d’un objet JSON.

Un Z-Objet consiste en une liste de paires Clé/valeur.

  • Chacune des valeurs d'une paire Clé/valeur est un Z-Objet.
  • Les valeurs peuvent être soit String (Z6), soit Reference (Z9), soit avoir tout autre type. Les valeurs String (Z6) et Reference (Z9) sont appelées valeurs terminales. Elles ne se développent pas davantage.
  • Un Z6/String a exactement deux clés, Z1K1/type avec la valeur "Z6", et Z6K1/string value, avec une chaîne arbitraire.
  • Une Reference (Z9) a exactement deux clés : Z1K1/type avec la valeur "Z9", et Z9K1/reference ID avec une chaîne représentant un ZID.
  • Chaque Clé ne peut apparaître qu’une fois dans chaque Z-Objet (mais peut réapparaître dans un Z-Objet encapsulé).

Les Z-Objets sont à la base des arbres de syntaxe abstraite.

S’il y avait un terme

TLDR

(« trop long : ne pas lire ») pour le projet, ce serait probablement « quelque chose comme LISP en JSON ».

Le but est de fournir une interface utilisateur facile qui permet la création et la manipulation des Z-Objets au moyen d’une interface wiki, et donc de créer un environnement de codage qui peut atteindre un large nombre de contributeurs et qui puisse devenir un projet Wikimédia avec une communauté active.

Chaque Z-Objet doit avoir une clé Z1K1/type avec une valeur qui s’évalue en un Z4/Type.

Nous utilisons la notation « Z-ID/libellé » pour nous référer aux Z-ID d’une façon plus ou moins agréable, où « Z-ID » est un identifiant de Z-Objet (ou une clé sur un tel objet) et « libellé » est le libellé en clair (par exemple en langue anglaise ou française) attaché à cette identifiant ou clé en langue neutre.

Dans la forme normale, un ZObject est représenté uniquement par des enregistrements de paires clé-valeur qui se terminent uniquement dans les noeuds terminaux. La forme normale d'un ZObject est généralement utilisée pour l'évaluation.

Forme canonique

Pour rendre les ZObjects plus lisibles et plus compacts, nous les stockons et les transmettons généralement sous une forme dite forme canonique.

Les formes canoniques utilisent trois transformations syntaxiques : pour Reference (Z9), String (Z6) et Typed list (Z881).

Références canoniques

Une référence pointe vers un ZObject via son ZID. Un ZID commence par la lettre Z, suivie d'un nombre naturel. La forme normale d'une référence ressemble à ceci :

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

La forme canonique remplace cet objet par une chaîne unique avec le ZID. La forme canonique de la référence ci-dessus est alors la suivante :

"natural number"
"Z10"

Notez que la forme normale et la forme canonique ont la même signification.

Chaînes canoniques

Une chaîne est une séquence de points de code Unicode, représentant généralement un mot ou un texte. Elle peut inclure des espaces et tout autre caractère en plus des caractères de contrôle.

La forme normale d'une chaîne est la suivante. Notez que la valeur de la seconde clé est bien sûr la chaîne elle-même, et non la version labellisée d'un ZID, comme on peut le voir sur le côté droit.

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

Les chaînes de caractères peuvent être mises sous forme canonique simplement par leur contenu en non pas l'objet entier. La chaîne ci-dessus peut être mise sous forme canonique ainsi.

"Wikifunctions"
"Wikifunctions"

Notez que les chaînes qui commencent par une lettre latine en majuscule et qui sont suivies d'un nombre naturel doivent être échappées car elles entreraient en collision avec la représentation normale d'une référence. Par exemple la chaîne "Z1" aurait la représentation suivante, à la fois sous sa forme normale et sous sa forme canonique. Ceci est dû au fait que, autrement, il serait ambigu de déterminer si "Z1" fait référence à la chaîne Z1 ou s'il est une référence à l'objet dont le ZID est Z1.

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

Listes canoniques

Les listes sont représentées par ce qu'on appelle des Benjamin Arrays. Vous trouverez leur description dans la section Z881/liste typée ci-dessous.

Représentation en JSON

Un Z-Objet peut être représenté en JSON en utilisant comme clés les clés ZID abstraites (Z1K1, etc.), et la représentation JSON de la valeur.

Une représentation plus lisible peut être donnée en remplaçant les clés abstraites et les Z-ID par leurs libellés dans une langue donnée, la représentation « libellée ». La version labellisée est souvent ambiguë et ne peut pas toujours être traduite sous une forme lisible par la machine.

La table suivante donne un exemple pour un Z-Objet qui représente l’entier positif 2. Sur la gauche nous voyons le Z-Objet libellé en anglais, au milieu libellé en allemand et à droite nous voyons le Z-Objet utilisant des Z-ID.

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

Comme vous pouvez le voir, les libellés ne sont pas nécessairement en anglais, mais doivent être dans l'une des plus de 300 langues que Wikifunctions prend en charge.

Forme normale

Pour le traitement des ZObjets par l’évaluateur, tous les ZObjets sont convertis en version normalisée décrite ci-dessus. La version normalisée est similaire à la version désérialisée, mais nous ne comptons sur aucune implication pour savoir s’il faut interpréter une valeur chaîne comme une Z6/Chaîne ou comme une Z9/Référence, mais elles sont toutes exprimées comme des ZObjets explicites.

Cela signifie que la représentation normalisée d’un ZObjet est un arbre dont toutes les feuilles sont soit de type Z6/Chaîne, soit de type Z9/Référence.

Cela signifie également que toutes les Listes sont représentées comme des ZObjets, et non comme des tableaux.

La forme normale suivante représente le ZObjet ci-dessus, qui a pour valeur l’entier naturel 2.

{
  "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"
   }
}

Les formes normales sont utilisées comme entrées pour le moteur d’évaluation. Elles assurent que l’entrée à évaluer est toujours uniforme et facile à traiter et que cela exige un nombre minimum de cas particuiers.

Persistant et transitoire

Tout ZObject de niveau principal stocké dans une page wiki Wikifunctions est un objet Persistent object (Z2) . Les ZObject qui ne sont pas stockés sur leur propre page wiki sont appelés ZObjects transitoires.

Chaque ZObject persistant doit avoir un Z2K1/id, un String (Z6) pour le ZID, ce qui est équivalent au nom de la page wiki où il est stocké. Supposons qu'il existe un ZObject pour le nombre naturel 2 que nous avons vu précédemment et qu'il est stocké sur la page Z702. Voici ce à quoi il pourrait ressembler (noter que les ZID de trois digits qui commencent avec Z7xx ne sont que des jokers, tant que nous n'avons pas les vrais ZID correspondants dans Wikifunctions).

{
  "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"
      }
    ]
  }
}

Tous les objets JSON stockés dans Wikifunctions le sont sous la forme C de normalisation Unicode. Toutes les valeurs avant l'évaluation doivent également être normalisées en Unicode à la forme normale C.

L'objet Persistent object (Z2) est une enveloppe fournissant des métadonnées pour le ZObject intégré à Z2K2/value.

Z2K3/label est un ZObject du type Multilingual text (Z12) qui a un Key (Z3), Z12K1/texts, pointant sur une liste de ZObjects Monolingual text (Z11) (rappelez-vous qu'une liste est représentée comme un tableau dans la représentation JSON). Le libellé sert à l'étiquetage.

Il y a d'autres Key (Z3) sur Persistent object (Z2) que nous avons omis ici. Ils sont tous définis sur Persistent object (Z2).

Z9/Références

Une Reference (Z9) est une référence à la valeur Z2K2/ du ZObject avec l'ID donné, et signifie que cette Z2K2/value a la même signification que la référence. Pour donner un exemple, prenez la référence suivante :

"two"
"Z702"

Ceci est la forme raccourcie d'une Reference (Z9) qui ressemblerait à cela dans sa forme développée (expliqué dans la section concernant la désérialisation) :

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

Et comme cet objet est une Reference (Z9) il doit être remplacé par la Z2K2/value du Persistent object (Z2) qui a "Z702" pour Z2K1/id (comme indiqué ci-dessus), il ressemblera donc à ceci :

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

Toutes les trois représentations JSON de cette section ont la même signification pour Wikifunctions. Ils se réfèrent tous au nombre naturel 2.

Notez que si une Z8/fonction a un type d'argument Z2/Objet persistant, alors, au lieu de la Z2K2/value, elle est remplacée par le Z2/Persistent object lui-même.

Z4/Types

Les types sont des ZObjects de type Z4/Type. Les ZObjects d'un type sont appelés des instances de ce type. Donc Z702/two que nous avons vu ci-dessus était une instance du type Z10/positive integer.

Le type nous indique comment interpréter une valeur. Le type nous fournit également les moyens de vérifier la validité d'un ZObject de ce type. Un type déclare habituellement les clés disponibles pour ses instances et une fonction utilisée pour valider les instances.

Voici le type pour les entiers naturels (simplifié car il saute la courte description et les alias et tout sauf les trois premières clés sur Z4/Type).

{
  "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"
      }
    ]
  }
}

Pour rendre le noyau du Type plus visible, regardons simplement le Z4/Type et enlevons les libellés :

{
  "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"
}

Le type Z10/positive integer définit dans Z4K2/keys la nouvelle représentation Key (Z3) Z10K1/base 10, que nous avions utilisée ci-dessus dans l'instance représentant le nombre 2.

Z4K3/validator pointe sur une Function (Z8) qui prend une instance comme argument et renvoie soit une erreur, soit la valeur elle-même dans le cas où il n'y a pas d'erreur. Si aucune erreur n'est renvoyée, l'instance a passé la validation avec succès. Dans le cas présent, la Function (Z8) pourrait effectuer les contrôles suivants :

  • Il n'y a qu'une et une seule clé, en représentation Z10K1/base 10, sur l'instance, en plus de Z1K1/type.
  • La valeur de la représentation de base 10 est de type String (Z6).
  • La représentation en base 10 ne contient que des chiffres.
  • La représentation en base 10 ne commence pas par un 0, sauf s'il s'agit du zéro.

Notez que toutes ces vérifications sont effectuées par Function (Z8) et proposées par les contributeurs, et que ces derniers peuvent définir et modifier tous les types. Rien n’est codé en dur concernant le type du nombre que nous utilisons ici.

Une instance pourrait utiliser des clés qui ne sont pas définies dans le Type. Il appartient à la fonction validateur de le permettre ou pas. Par exemple, les instances de Z7/Appel de fonction utilisent souvent des clés non définies sur Z7/Appel de fonction, comme on peut le voir dans la section sur Z7/Appel de fonction. Néanmoins il est cependant attendu que la plupart des valideurs exigent que toutes les clés soit définies.

Mais un petit nombre d'élements sont codés en dur, tel que le comportement d’un Z7/appel de fonction. Plus de détails viendront ultérieurement.

Z3/Clés

Toutes les clés doivent avoir un K suivi par un nombre naturel et peuvent être précédées par un Z-ID. Si elles sont précédées d'un Z-ID, elles sont appelées clés globales, si elles ne le sont pas elles sont appelées clés locales. Par exemple les deux représentations suivantes sont équivalentes.

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

Les clés globales sont des arguments nommés alors que les clés locales sont des arguments positionnels.

  • La règle de base est d'utiliser les clés globales à chaque fois que c'est possible.
  • L'utilisation principale pour les clés locales est quand une Z8/Fonction ou un Z4/Type est créé à la volée, et ne peut donc pas avoir de clé globale parce que la Z8/Fonction ou le Z4/Type créé n'est lui-même pas persistant.

Une clé globale est toujours définie sur le ZObject sur lequel la partie ZID de son identifiant fait référence. Dans la définition, une clé contient des informations sur le type d'objet qu'elle doit contenir (Z3K1), l'ID global qui identifie cette clé (Z3K2), ses libellés lisibles par un humain (Z3k3) et l'indication que cette clé est un champ d'identité (Z3K4) ou pas.

Une clé d'identité permet aux objets de stocker leur ID persistant. Par exemple, les fonctions et types contiennent un champ d'identité. Les types envisagés, en particulier les énumérations, ainsi que les caractéristiques grammaticales, nécessitent également une identité.

Enumérations

Une énumération est un type qui a un nombre limité de valeurs. Les exemples d'énumérations sont le type Boolean (avec les valeurs "false" et "true") ou le signe des entiers (avec des valeurs "positif", "neutre" ou "négatif"). Les énumérations sont aussi un outil important pour prendre en charge les fonctions linguistiques.

Chaque type d'énumération a une clé qui est marquée comme un champ d'identité. Par exemple, voyons la définition du type pour Boolean (en supprimant les libellés des clés pour simplifier) :

{
    "type": "Type",
    "identity": "Boolean",
    "keys": [
        "Key",
        {
            "type": "Key",
            "value type": "Boolean",
            "key id": "Z40K1",
            "label": { /* "identity" */ },
            "is identity": "True"
        }
    ],
    ...
}
{
    "Z1K1": "Z4",
    "Z4K1": "Z40",
    "Z4K2": [
        "Z3",
        {
            "Z1K1": "Z3",
            "Z3K1": "Z40",
            "Z3K2": "Z40K1",
            "Z3K3": { /* "identity" */ },
            "Z3K4": "Z41"
        }
    ],
    ...
}

Toutes les valeurs limitées pour Boolean attribueront leur ZID à la valeur de leur clé d'identité/Z40K1. Voir, par exemple, True, qui contient son identité et en plus les données multilingues (nom, description, alias) comme partie des clés d'objet persistant.

{
	"type": "Persistent object",
	"identity": {
		"type": "String",
		"value": "Z41"
	},
	"value": {
		"type": "Boolean",
		"identity": "True"
	},
	"labels": {
		"type": "Multilingual text",
		"texts": [
			"Monolingual text",
			{
				"type": "Monolingual text",
				"language": "English",
				"text": "true"
			}
		]
	}
}
{
	"Z1K1": "Z2",
	"Z2K1": {
		"Z1K1": "Z6",
		"Z6K1": "Z41"
	},
	"Z2K2": {
		"Z1K1": "Z40",
		"Z40K1": "Z41"
	},
	"Z2K3": {
		"Z1K1": "Z12",
		"Z12K1": [
			"Z11",
			{
				"Z1K1": "Z11",
				"Z11K1": "Z1002",
				"Z11K2": "true"
			}
		]
	}
}

Enumérations de faible poids

Tout comme les énumérations de la section précédente, une énumération réduite est un type qui possède un nombre limité de valeurs. Néanmoins avec les différences suivantes :

  • Chaque valeur correspond à une entité Wikidata.
  • Les valeurs sont référencées par rapport à l'utilisation de leurs indentifiants Wikidata. Ceci est fait en utilisant les types de références Wikidata (chaque instance d'un type de référence contient un identifiant Wikidata).
  • En conséquence, il n'est pas nécessaire de créer un ZObject pour chaque valeur (le seul ZID créé pour une petite énumération est celui du type d'énumération lui-même).

Lorsqu'un type de petite énumération est créé, l'utilisateur indique le type de référence que Wikidata doit utiliser pour spécifier les valeurs, et l'interface utilisateur aide le créateur à saisir les valeurs ainsi que les instances de ce type de référence. La définition du type d'énumération lorsqu'elle est enregistrée, contient la liste de toutes ces valeurs.

Formellement, chaque type de petite énumération est un appel à Z6884 - une fonction dont le but est de créer ces types (de cette façon, c'est similaire à d'autres fonctions de création de type comme Z881). La définition d'un type de petite énumération capture ensuite les détails de l'appel à Z6884.

Voici un exemple qui utilise la référence d'un élément Wikidata pour spécifier 3 valeurs possibles pour le genre grammatical : masculin, féminin et neutre. Ce type existe dans Wikifunctions sous Z25501. Le type ZObject (qui apparaît comme la valeur de Z2K2 dans la définition persistante) est indiqué juste en dessous. Dans cet exemple Z6884K1 spécifie la référence de l'élément Wikidata comme le type utilisé pour énumérer les valeurs, et Z6884K2 indique la liste de ces valeurs. Z6884K3 est simplement une auto-référence du type, qui passe son propre ZID en tant que chaîne.

{
    "type": "Function call",
    "function": "Typed enum of Wikidata references",
    "Wikidata reference type": "Wikidata item reference",
    "list of Wikidata references": [
        "Wikidata item reference",
		{
            "type": "Wikidata item reference",
            "Wikidata item id": "masculine"
        },
		{
            "type": "Wikidata item reference",
            "Wikidata item id": "feminine"
        },
		{
            "type": "Wikidata item reference",
            "Wikidata item id": "neuter"
        }
    ],
    "ZID of result type (assigned by WikiLambda)": {
		"type": "String",
		"value": "Z25501"
	}
}
{
    "Z1K1": "Z7",
    "Z7K1": "Z6884",
    "Z6884K1": "Z6091",
    "Z6884K2": [
        "Z6091",
		{
            "Z1K1": "Z6091",
            "Z6091K1": "Q524410"
        },
		{
            "Z1K1": "Z6091",
            "Z6091K1": "Q24004467"
        },
		{
            "Z1K1": "Z6091",
            "Z6091K1": "Q24004469"
        }
    ],
    "Z6884K3": {
		"Z1K1": "Z6",
		"Z6K1": "Z25501"
	}
}

Chaque instance d'un type de d'énumération légère contient seulement une propriété Z1K1 qui fait référence au ZID du type lui-même, et une propriété ...K1 dont la valeur est l'un des éléments de la liste des valeurs. L'instance de Z25501 pour le genre féminin ressemble à :

{
    "type": "Grammatical gender (m/f/n)",
    "element": {
        "type": "Wikidata item reference",
        "Wikidata item id": "feminine"
    }
}
{
    "Z1K1": "Z25501",
    "Z25501K1": {
        "Z1K1": "Z6091",
        "Z6091K1": "Q24004467"
    }
}

Encore une fois, les instances ne sont jamais rendues persistantes (et donc ne reçoivent pas de ZID). L'interface utilisateur permet de spécifier une instance éphémère lorsque c'est nécessaire (par exemple, comme entrée d'une fonction).

Z8/Fonctions

Dans la définition de Z10/natural number nous avons vu une première référence à Function (Z8), Z110/validate natural number. Ici, nous allons utiliser une fonction beaucoup plus simple, Z781/add. Z781/add est une Function (Z8), qui prend deux nombres Z10/natural number et renvoie un Z10/natural number.

Nous ne montrons que la valeur.

{
 "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"
}

Pour rester concis, nous avons supprimé les Z17K3/labels des déclarations Argument declaration (Z17), qui sont identifiées à l'aide des identifiants Z17K2/key. Mais comme les Key (Z3) sur Type (Z4), ils ont des libellés dans toutes les langues prises en charge. Les clés sont globales lorsque la Function (Z8) est persistante et locales lorsqu'elle est transitoire.

La fonction est spécifiée dans la documentation (omise), mais aussi dans les Z8K3/tests et les Z8K1/déclarations de type sur les arguments et le Z8K2/return type. En outre, comme une fonction peut avoir plusieurs Z8K4/Implementations, les Implementations se confirment mutuellement.

Dans les circonstances normales, Z8K5/identité est censée être une chaîne identique au ZID de la fonction et au titre de la page.

Il n'est pas autorisé aux Function (Z8) d'avoir des effets de bord de changment d'état.

Z7/Appels de fonctions

Le ZObject suivant représente l'appel d'une fonction. A la deuxième ligne, nous voyons une représentation plus compacte de l'appel de fonction, qui utilise une syntaxe qui nous est plus familière pour les appels de fonction.

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

En utilisant des littéraux au lieu de ZObjects persistants pour les arguments, cela ressemblerait à ceci :

  • Notez que nous créons les littéraux en utilisant le Z10/positive integer comme constructeur.
  • Tous les Type (Z4) peuvent être appelés ainsi en fournissant une valeur à chacune de leur clé.
  • Il ne s'agit pas d'un appel de Function call (Z7), mais d'une notation pour l'objet de Type (Z4) donné.
{
  "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">)

Lorsque cet appel de Function call (Z7) est évalué, il se résoud comme prévu dans la valeur quatre.

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

L'évaluation est réalisée à plusieurs reprises sur le résultat de l'évaluation jusqu'à ce qu'un point fixe soit atteint.

Z14/Mises en œuvre

Chaque Function (Z8) peut avoir un certain nombre de Implementation (Z14) différentes. Il existe trois types principaux d' Implementation (Z14) : intégrées, Code (Z16), ou par composition d'autres Function (Z8) .

Examinons la fonction Z781/add et quatre différentes implémentations de la fonction Implementation (Z14).

Mises en œuvre intégrées

Une implémentation intégrée indique à l'évaluateur de renvoyer un résultat d'évaluation approprié. Les constructions intégrées sont codées en dur dans l'évaluateur. Z14K4/builtin fait référence à l'ID de construction avec le code en dur (qui doit être le ZID de l'objet Persistent object (Z2)).

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

Un évaluateur est conscient des constructions intégrées dont il dispose et il peut les utiliser à volonté. Notez que l'addition ne serait pas une fonction qui aurait une construction intégrée. Cet exemple ici est purement illustratif.

Z16/Code

Une implémentation en Code (Z16) représente un extrait de code dans un langage de programmation donné.

{
  "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"
  }
}

L'évaluateur saura transformer les ZObjects donnés représentant les arguments dans les langages de programmation pris en charge, comment exécuter la séquence de code fournie, puis comment retransformer le résultat en un ZObject qui le représente.

Eventuellement, la traduction des ZObjects en valeurs natives des langages de programmation supportés serait à la charge de Wikifunctions lui-même (ce qui nécessite d'être décrit dans un autre document). Jusqu'ici nous ne prenons en charge que Code (Z16) pour les arguments et les types de retour intégrés qui sont supportés en dur par l'évaluateur.

Z46 / Désérialiseur

Un Type converter to code (Z46) prend un ZObject d'un type spécifique et le transforme en une valeur pour un langage de programmation donné.

Par exemple, les Type converter to code (Z46) suivants prennent un ZObject de type Z10/natural number et le transforment en une valeur BigInt JavaScript.

{
  "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"
}

Le Z46K4/native type indique le type produit par le désérialiseur. Cela nous permet d'utiliser des implémentations naturelles comme celles ci-dessus pour l'addition.

Z64 / Sérialiseur

Le fonctionnement inverse d'un Type converter to code (Z46) est celui du Type converter from code (Z64). Un Type converter from code (Z64) prend une valeur dans le langage de programmation donné et la transforme en un ZObject du type demandé.

{
  "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"
}

Composition

La Implementation (Z14) la plus portable (mais souvent aussi la plus lente) est réalisée via la composition d'autres Function (Z8).

Nous montrons à la fois le ZObject de l'implémentation, ainsi qu'une notation plus facile à lire basée sur la syntaxe d'appel de fonction.

{
 "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)
  )
)

Cette composition repose sur un certain nombre d'autres Function (Z8) : Z782/is zero, Z783/successor, Z784/predecessor, Echo (Z801) et le plus intéressant lui-même. Il est tout à fait normal qu'une Implementation (Z14) appelle sa propre Function (Z8) récursivement. Notez cependant que l'évaluateur n'a pas à appeler la Implementation (Z14) recursivement un évaluateur est libre de choisir l'implémentation à chacune des étapes de la récursion.

C'est tout sauf rapide mais cela nous permet d'utiliser un formalisme bien compris et une implémentation très simple pour s'assurer que les autres implémentations de Z781/add sont correctes certes, probablement moins intéressantes pour l'ajout, mais nous pouvons imaginer qu'il existe des Function (Z8) qui ont des implémentations plus évidemment correctes, plus intelligentes et plus rapides. Wikifunctions peut tester ces implementations de manière croisée et nous apporter ainsi une sécurité sur leur véracité.

Evaluation d'exemples

Dans la suite nous évaluons la composition ci-dessus. Nous commençons par l'appel suivant de Function call (Z7) (nous ne nous attachons qu'à la syntaxe fonctionnelle en raison de sa brièveté).

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

Nous remplaçons l'appel de fonction par la composition donnée ci-dessus, et remplaçons les arguments par les valeurs données. Ce qui donne le code suivant :

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">)
  )
)

Nous évaluons Z782/is zero (Z10/Natural number<"2">) par rapport à la valeur Boolean (Z40) de false (Z42) (puisque 2 n'est pas zéro). Ce qui donne :

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">)
  )
)

Cela nous permet de remplacer l'appel de Z802/if par Z802K3/alternative, puisque Z802K1/condition est fausse. Ce qui donne :

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

La fonction Z783/successor ajoute simplement 1 au nombre, et la fonction Z784/predecessor lui soustrait 1. L'une ou l'autre de ces fonctions peut ou non être implémentée dans le code ou d'une autre manière, cela n'a pas vraiment d'importance. Si nous remplaçons ces deux appels de fonctions, nous obtenons l'appel suivant :

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

Nous remplaçons à nouveau l'appel à Z781/add par sa composition, et remplaçons les arguments par les nouvelles valeurs. Ce qui donne :

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">)
  )
)

Nous vérifions à nouveau si la valeur donnée à Z782/is zero est zéro (ce n'est pas la cas, c'est un). Donc nous remplaçons l'appel à Z782/is zero à nouveau par false (Z42).

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">)
  )
)

Puisque Z802K1/condition est à nouveau faux, nous remplaçons l'appel à Z802/if par Z802K3/alternative

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

Encore une fois, nous remplaçons les appels de fonction à Z783/successor et Z784/predecessor par les résultats respectifs, un nombre de plus, un nombre de moins.

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

Nous sommes à nouveau à l'étape où nous remplaçons l'appel à Z781/add par sa composition. Ce qui donne :

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">)
  )
)

L'appel à Z782/is zero maintenant a l'argument Z10/natural number<"0"> qui est bien sûr zéro. Donc l'appel à Z782/is zero fournit un true (Z41). Ce qui donne :

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">)
  )
)

L'appel à la fonction Z802/if a maintenant une Z802K1/condition true (Z41), ce qui signifie que nous remplaçons l'ensemble de l'appel par Z802K2/consequence, et non pas Z802K3/alternative. Ce qui donne :

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

C'est un point fixe, c'est-à-dire qu'il ne change pas lorsqu'il est évalué, et donc c'est le résultat de notre appel de fonction.

2 et 2 font 4.

Ordre d’évaluation

L’ordre d’évaluation est laissé au gré de l’évaluateur. Puisque toutes les Z8/Fonctions ne sont pas autorisées à avoir des effets de bord, ceci conduira toujours au même résultat. Mais une stratégie d’évaluation imprudente peut conduire à bien plus de calculs que nécessaire ou même conduire l’évaluateur à ne jamais se terminer. Z722/ajouter récursivement nous fournit un exemple qui peut se terminer avec une boucle sans fin si nous essayons un ordre complet d’évaluation :

Pour l’appel à Z802/si dans Z722/ajouter récursivement, il serait imprudent d’évaluer d'abord tous les trois arguments et de renvoyer ensuite le deuxième ou le troisième argument. Selon la Z802K1/condition sur le premier argument, nous avons besoin de retourner uniquement soit le Z802K2/conséquent, soit la Z802K3/alternative. Il n’y aura jamais de cas où nous avons besoin d’évaluer à la fois le deuxième et le troisième argument.

En fait, nous pourrions même renvoyer le deuxième ou le troisième argument non évalué. Souvenez-vous que l’évaluateur évaluera chaque résultat à nouveau de toute façon jusqu’à ce qu’un point fixe soit atteint. Aussi, Z802/si peut être mise en œuvre de façon paresseuse, en enlevant la branche inappropriée, et en ne renvoyant que la branche appropriée en tant que ZObject non évalué.

Une stratégie paresseuse d'évaluation est en général recommandée, mais par exemple quand l’évaluateur veut utiliser une implémentation basée sur Z16/Code, ceci pourrait ne pas être réalisable. Et alors l’évaluateur pourrait décider d’évaluer d’abord les arguments puis ensuite l’appel englobant. En fin de compte, il existe des opportunités pour expérimenter différentes stratégies d’évaluation.

Z20/Testeurs

Les Test case (Z20) sont des ZObjects qui font un Z20K2/call et utilisent ensuite un Z20K3/validator sur le résultat. Z20K3/Validator est un appel incomplet de Function call (Z7) qui fournit le résultat de Z20K2/call injecté comme premier argument. Si Z20K3/validator renvoie Z41/true, alors Z20/Tester a réussi, sinon c'est un échec.

Les tests sont utilisés pour s'assurer que toutes les Z14/implémentations se comportent comme attendu et doivent être considérées comme équivalentes aux tests unitaires. Une Z8/Funktion doit lister tous les Z20/Tester à passer pour qu'une Z14/Implémentation soit conforme. En outre, les différentes Z14/implémentations peuvent être mutuellement testées pour s'assurer de leur cohérence.

{
 "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"
 }
}

Dans ce cas, nous évaluons d'abord Z20K2/call qui est Z781/add(Z702/two, Z702/two), dont le résultat est Z10/Natural number<"4">. Ce qui, à son tour, est ensuite utilisé dans le valideur Z20K3/result, où il est injecté comme premier argument, ce qui donne Z788/natural number equality(Z10/Natural number<"4">, Z704/four). Cette appel doit renvoyer Z41/true, et donc Z20/Tester doit être passé avec succès.

Types génériques

Un type générique est réalisé par un appel Z7/Fonction à un Z8/Fonction qui prend quelques arguments et renvoie un Z4/Type.

Par exemple, Z882/type pair est une fonction qui prend deux Z4/Type comme arguments, un pour le premier et un pour le deuxième élément, et qui renvoie un Z4/Tyme en ligne. Donc pour faire une paire de nombres Z10/Natural, nous appelons Z882/typed pair(Z10/Natural number, Z10/Natural number) et le résultat est un Z4/Type que nous pouvons utiliser pour le champ Z1K1 d'un 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"
}

Le résultat de l'appel Z7/Fonction est un Z4/Type créé dynamiquement qui garantit que les deux éléments de la paire ont le bon Z4/Type. Le résultat de ce Z7/Appel de fonction ressemble à ceci.

{
 "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"
}

Ceci est également un exemple de l'utilisation du champ Z4K1/identité sur Z4/Type : il décrit comment Z4/Type a été créé, et nous permet d'accéder aux arguments utilisés pour la création du type. La conservation de ces informations en déclaration est très utile pour valider un appel de fonction de manière statique et pour comparer les types.

Si nous voulons une paire Z882/Typed qui ne restreint pas le Z4/Type de l'un, l'autre ou des deux éléments, on pourrait appeler la fonction Z882/Typed pair avec Z1/ZObject pour l'un ou les deux arguments.

Z881/Listes typées

Voici une liste de deux chaînes.

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

Si nous transformons ceci en Z-Objets, cela ressemble à ce qui suit.

{
 "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"
 }
}

Un littéral de tableau JSON commence toujours par le type utilisé pour la Z881/liste typée. Ce n'est pas le premier élément de la liste mais simplement le type de la liste typée. Ces tableaux sont appelés Benjamin Arrays. Si nous voulons une liste non typée nous utilisons Z1/Object comme argument. Une liste non typée vide ressemblerait à :

[
 "object"
]
[
 "Z1"
]

Z22/Résultat dévaluation

Un appel de Z7/Fonction exécuté dans Wikifunctions renvoie toujours un objet de type Z22/Résultat d'évaluation.

Un objet de résultat d'évaluation contient toujours la valeur renvoyée à la suite de l'exécution d'un appel de fonction et une collection de métadonnées recueillies lors de l'évaluation. Voici un exemple d'une réponse réussie :

{
    "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"
            }
        ]
    }
}

Si l'évaluation échoue, le champ de réponse contiendra Z24/Void, tandis que le champ de métadonnées contiendra une clé "erreur" avec les détails de l'échec. Ceci est un exemple d'objet résultat d'une évaluation qui n'a pas réussi :

{
    "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"
                    }
                }
            }
        ]
    }
}

Ces exemples ne sont que des versions condensées des objets de résultats d'évaluation réels et ne contiennent qu'une seule clé d'exemple dans le champ Metadata. Dans les exemples réels, la collecte de métadonnées renvoie toutes les métriques collectées par les services du serveur, y compris la durée de l'exécution, l'utilisation du processeur et celle de la mémoire.

Pour une description plus détaillée des métadonnées possibles renvoyées dans l'objet de résultat d'évaluation, voir le Guide des métadonnées d'appel de fonction dans Mediawiki.

Z5/Erreurs

Un Z7/Appel de fonction peut rencontrer une Z5/Erreur. Ceci apparaît lorsque l'appel à la fonction ne peut s'exécuter correctement et n'est pas récupérable (par exemple une division par zéro ou le manque de mémoire).

Error (Z5) est un type générique. Chaque instance de Z5 référence le ZID d'un type d'erreur (dans le Z5K1/error type), et ce type d'erreur détermine le type de Z5K2/error value, et les clés qui y seront présentes. Chaque type d'erreur est une instance de Error type (Z50) et les ZID Z500-Z599 sont réservés aux types d'erreurs.

Voir les informations complémentaires sur Représentation des erreurs.

Z99/Quote

Quote (Z99) est utilisé pour envelopper un ZObject afin qu'il ne soit pas évalué ("résolu"). (ceci est similaire au fait de mettre des guillemets en Lisp). Z99/Quote a une clé unique Z99K1/quotation, du type Z1/Object.

Pour illustrer, certaines parties des objets d'erreur (instances de Z5/Error) sont entre guillemets lorsqu'elles sont créées lors de l'exécution d'un appel de fonction. Par exemple, une erreur de type Z507/Error dans l'évaluation comprend une copie entière de l'appel à la fonction dont l'exécution a causé l'erreur (comme la valeur de l'appel de Z507K1/function). Comme cette appel de fonction est très susceptible d'être malformé d'une certaine manière, nous nous assurons qu'aucune autre tentative n'est faite pour l'évaluer, en le plaçant entre guillemets dans l'objet d'erreur. (ainsi le type de Z507K1 est déclaré comme étant Quote (Z99) et sa valeur est toujours entre guillemets).

Nous utilisons les règles suivantes pour l'utilisation de Quote (Z99) :

  1. Placer un ZObject entre guillemets si nous pensons qu'il peut être non valide d'une certaine manière.
  2. Mais ne le faisons pas pour Z1K1 lui-même. Si sa valeur est douteuse, il faut mettre des guillemets autour de l'objet entier qui la contient.
  3. Mettre entre guillemets les clés résolvables (clés dont les valeurs contiennent des instances de Function call (Z7), Reference (Z9) ou Argument reference (Z18)) qui pourraient ne pas être adaptées en entrée d'une fonction.
  4. Les guillemets lors de la résolution d'une valeur pourraient causer une catastrophe (récursion infinie par exemple).

Note : à mesure que notre stratégie de résolution évolue, il est possible que (3) et (4) deviennent inutiles.

Fonctions non opérationnelles

Aucune Z8/Fonction n’est autorisée à avoir des effets de bord. Toutes les Z8/Fonctions doivent être fonctionnelles. Cela veut dire qu’elles doivent renvoyer les mêmes valeurs lorsqu’elles sont appelées avec les mêmes paramètres. Cela signifie que des Z8/Fonctions comme « renvoyer un nombre aléatoire » ou « renvoyer l’horodatage actuel » sont impossibles.

This might change in the future. Ce sera traité dans un document ultérieur.

Zx/Types sommes

Un type générique particulièrement utile est le Zx/Type somme (ou Type agrégat), qui prend une liste de Z4/Types et renvoie un Z4/Type qui prend exactement une seule instance des types donnés.

Ceci permettra également d'avoir des paramètres facultatifs dans les appels de fonctions.

Ce sera traité dans un document ultérieur.

Quelques questions et tâches à faire

  • Avons-nous besoin de « nécessaire / option » pour des clés quelconques au début ? — non.
  • Remplacer les valeurs par défaut sur Z3/Clé par Zx/Sum (ou au moins rendre ceci cohérent avec la Z17/déclaration de paramètre) ?
  • Pourrait être laissé à faire plus tard si nous n ’avons pas besoin de Z3 pour le moment.
  • Notez que tout est en Unicode et que tout correspond à la normalisation requise par MediaWiki
  • Réécrire l'introduction pour commencer par la normale puis canoniser

Voir aussi