Nous concevons un langage de programmation multi-paradigme. Partie 4 - Constructions de base du langage de modélisation

Nous continuons l'histoire de la création d'un langage de programmation multi-paradigme qui combine un style déclaratif avec un style orienté objet et fonctionnel, ce qui serait pratique lorsque vous travaillez avec des données semi-structurées et intégrez des données provenant de sources disparates. Enfin, après l' introduction et la revue des technologies multi-paradigmes existantes et des langages de représentation des connaissances, nous sommes arrivés à la description de la partie du langage hybride qui est responsable de la description du modèle de domaine. Je l'ai nommé le composant de modélisation .



Le composant de modélisation est destiné à une description déclarative d'un modèle de domaine sous la forme d'une ontologie - un réseau d'instances de données (faits) et de concepts abstraits interconnectés par des relations. Il est basé sur la logique de trame - un hybride d'une approche orientée objet de la représentation des connaissances et de la logique du premier ordre. Son élément principal est un concept qui décrit un objet modélisé à l'aide d'un ensemble d'attributs. Le concept est construit sur la base d'autres concepts ou faits, les concepts initiaux seront appelés parentaux , le dérivé - enfant... Les relations lient les valeurs des attributs des concepts enfant et parent ou limitent leurs valeurs possibles. J'ai décidé d'inclure les relations dans la définition du concept, afin que toutes les informations à ce sujet soient, si possible, au même endroit. Le style de syntaxe des définitions de concept sera similaire à celui de SQL - les attributs, les concepts parents et les relations entre eux doivent être séparés en différentes sections.



Dans cet article, je souhaite présenter les principales manières de définir des concepts.



Premièrement, un concept qui se construit en transformant les concepts parentaux .

Deuxièmement, le style orienté objet implique l' héritage , ce qui signifie que vous avez besoin d'un mécanisme qui vous permet de créer un concept en héritant des attributs et des relations des concepts parents, en les développant ou en les réduisant.



Troisièmement, je crois qu'un mécanisme serait utile pour définir la relation entre les concepts des pairs - sans se diviser en concepts enfants et parents.

Passons maintenant à un examen détaillé des principaux types de composants de modélisation.



Commençons par les faits



Les faits représentent une description de connaissances spécifiques sur un domaine sous la forme d'un ensemble nommé de paires clé-valeur:



fact < > {
	< > : < >
	...	
}


Par exemple:



fact  product {
	name: “Cabernet Sauvignon”,
	type: “red wine”,
	country: “Chile”
}


Le nom de fait peut ne pas être unique, par exemple, il peut y avoir de nombreux produits avec différents noms, types et pays d'origine. Nous considérerons les faits comme identiques si leurs noms et les noms et valeurs de leurs attributs coïncident.



Une analogie peut être établie entre les faits du composant de modélisation et les faits du langage Prolog. Ils ne diffèrent que par la syntaxe. Dans Prolog, les arguments de fait sont identifiés par leur position et les attributs des faits du composant de modélisation sont identifiés par leur nom.



Concepts



Un concept est une structure qui décrit une entité abstraite et est basée sur d'autres concepts et faits. La définition d'un concept comprend un nom, des listes d'attributs et des concepts enfants. Et aussi une expression logique décrivant les dépendances entre ses attributs (concept enfant) et les attributs des concepts parents, vous permettant de déduire la valeur des attributs du concept enfant:



concept < > < > (
		< > = <>,
		...	
) 
from 
	<  > <  > (
		< > = <> 
	   	...
	 ),
where < >


Un exemple de définition du profit en fonction des revenus et des coûts :



concept profit p (
	value = r.value – c.value,
	date
) from revenue r, cost c
where p.date = r.date = c.date


La définition d'un concept est similaire dans sa forme à une requête SQL, mais au lieu du nom de la table, vous devez spécifier les noms des concepts parents et, au lieu des colonnes renvoyées, les attributs du concept enfant. De plus, un concept a un nom par lequel il peut être référencé dans les définitions d'autres concepts ou dans les requêtes de modèle. Le concept parent peut être soit le concept lui-même, soit les faits. L'expression de relation dans la clause where est une expression booléenne qui peut inclure des opérateurs logiques, des conditions d'égalité, des opérateurs arithmétiques, des appels de fonction, etc. Leurs arguments peuvent être des variables, des constantes et des références à des attributs des concepts parents et enfants. Les références d'attribut ont le format suivant:



< >.< >


Par rapport à la logique cadre, dans la définition d'un concept, sa structure (attributs) est combinée avec des relations avec d'autres concepts (concepts parents et expression de relations). De mon point de vue, cela vous permet de rendre le code plus compréhensible, puisque toutes les informations sur le concept sont collectées en un seul endroit. Il est également conforme au principe d'encapsulation en ce sens que les détails de mise en œuvre d'un concept sont cachés dans sa définition. A titre de comparaison, un petit exemple dans le langage de la logique de trame peut être trouvé dans la publication précédente .



L'expression des relations a une forme conjonctive (se compose d'expressions reliées par des opérations logiques "ET") et doit inclure des conditions d'égalité pour tous les attributs du concept enfant, suffisantes pour déterminer leurs valeurs. En outre, il peut inclure des conditions qui limitent la signification des concepts parents ou les relient. Si tous les concepts parents ne sont pas liés dans la clause where , le moteur d'inférence renvoie toutes les combinaisons possibles de leurs valeurs en conséquence (similaire à l'opération FULL JOIN en SQL).



Pour plus de commodité, certaines des conditions d'égalité des attributs peuvent être placées dans la section des attributs des concepts enfant et parent. Par exemple, dans la définition du profit, la condition de l'attributvalue est déplacée vers la section des attributs et pour l'attribut de date, elle est laissée dans la section where . Vous pouvez également les transférer à la de la section :



concept profit p (
	value = r.value – c.value,
	date = r.date
) from revenue r, cost c (date = r.date)


Ce sucre syntaxique vous permet de rendre les dépendances entre les attributs plus explicites et de les distinguer des autres conditions.



Les concepts suivent les règles de Prolog mais ont une sémantique légèrement différente. Prolog se concentre sur la construction d'énoncés et de questions logiquement liés. Les concepts sont principalement destinés à structurer les données d'entrée et à en extraire des informations. Les attributs de concept correspondent aux arguments des termes Prolog. Mais si dans Prolog le terme arguments est lié à l'aide de variables, alors dans notre cas, les attributs sont directement accessibles par leurs noms.



Puisque la liste des concepts parents et les conditions de la relation sont séparées en sections séparées, l'inférence sera légèrement différente de celle de Prolog. Je décrirai en général son algorithme. Les concepts parents seront affichés dans l'ordre dans lequel ils sont spécifiés dans la section from . La recherche d'une solution pour le concept suivant est effectuée pour chaque solution partielle des concepts précédents de la même manière que dans la résolution SLD. Mais pour chaque solution partielle, la validité de l'expression de relation de la clause where est vérifiée... Puisque cette expression est sous forme de conjonction, chaque sous-expression est testée séparément. Si la sous-expression est fausse, alors cette solution partielle est rejetée et la recherche passe à la suivante. Si certains des arguments de sous-expression ne sont pas encore définis (non associés à des valeurs), sa validation est reportée. Si la sous-expression est un opérateur d'égalité et qu'un seul de ses arguments est défini, le système d'inférence trouvera sa valeur et tentera de l'associer à l'argument restant. Ceci est possible si l'argument libre est un attribut ou une variable.



Par exemple, lors de l'affichage des entités du concept de profit , les entités du concept de revenu seront d'abord trouvées , et, en conséquence, les valeurs de ses attributs. Alors l'égalité p.date = r.date = c.datedans la section where vous permettra d'associer des attributs de date et d'autres concepts à des valeurs . Lorsque la recherche logique arrive au concept de coût , la valeur de son attribut date sera déjà connue et sera l'argument d'entrée pour cette branche de l'arbre de recherche. Je prévois de parler en détail des algorithmes d'inférence dans l'une des prochaines publications.



La différence avec Prolog est que dans les règles Prolog, tout est des prédicats - et des appels à d'autres règles et prédicats intégrés d'égalité, de comparaison, etc. Et l'ordre de leur vérification doit être spécifié explicitement, par exemple, les deux premières règles doivent disparaître, puis l'égalité des variables:



profit(value,date) :- revenue(rValue, date), cost(cValue, date), value = rValue – cValue


Dans cet ordre, ils seront exécutés. Le composant de modélisation suppose que tous les calculs de conditions dans la clause where sont déterministes, c'est-à-dire qu'ils ne nécessitent pas de plongée récursive dans la branche de recherche suivante. Comme leur calcul ne dépend que de leurs arguments, ils peuvent être calculés dans un ordre arbitraire car les arguments sont liés à des valeurs.



À la suite de l'inférence, tous les attributs du concept enfant doivent être associés à des valeurs. Et aussi l'expression des relations doit être vraie et ne pas contenir de sous-expressions indéfinies. Il convient de noter que la dérivation des concepts parentaux ne doit pas être couronnée de succès. Il existe des cas où il est nécessaire de vérifier l'échec de la dérivation du concept parent à partir des données source, par exemple, dans les opérations de négation. L'ordre des concepts parents dans la section from détermine l'ordre dans lequel l'arbre de décision est parcouru. Cela permet d'optimiser la recherche d'une solution, à commencer par les concepts qui limitent plus fortement l'espace de recherche.



La tâche de l'inférence logique est de trouver toutes les substitutions possibles d'attributs du concept enfant et de représenter chacune d'elles comme un objet. Ces objets sont considérés comme identiques si les noms de leurs concepts, noms et valeurs d'attribut correspondent.



Il est considéré comme acceptable de créer plusieurs concepts avec le même nom, mais avec des implémentations différentes, y compris un ensemble d'attributs différent. Il peut s'agir de différentes versions du même concept, de concepts connexes pouvant être combinés sous un même nom, de concepts identiques provenant de sources différentes, etc. Dans la conclusion logique, toutes les définitions existantes du concept seront prises en compte et les résultats de leur recherche seront combinés. Plusieurs concepts portant le même nom sont analogues à la règle de Prolog, dans laquelle une liste de termes a une forme disjonctive (les termes sont OR).



Héritage de concept



L'une des relations les plus courantes entre les concepts est les relations hiérarchiques telles que genre-espèce. Leur particularité est que les structures des concepts enfant et parent seront très similaires. Par conséquent, la prise en charge du mécanisme d'héritage au niveau de la syntaxe est très importante; sans elle, les programmes seront pleins de code répétitif. Lors de la construction d'un réseau de concepts, il serait pratique de réutiliser à la fois leurs attributs et leurs relations. Bien que la liste des attributs soit facile à étendre, raccourcir ou redéfinir certains d'entre eux, la relation est plus compliquée avec la modification des relations. Puisqu'il s'agit d'une expression logique sous forme conjonctive, il est facile d'y ajouter des sous-expressions supplémentaires. Cependant, la suppression ou la modification peut nécessiter des complications de syntaxe importantes. Les avantages ne sont pas si évidentspar conséquent, nous reporterons cette tâche à l’avenir.



Vous pouvez déclarer un concept basé sur l'héritage en utilisant la construction suivante:



concept < > < > is 
	<  > <  > ( 
		< > = <>, 
		...
	 ),
	...
with < > = <>, ...
without <  >, ...
where < >


La section is contient une liste de concepts hérités. Leurs noms peuvent être spécifiés directement dans cette section. Ou, spécifiez la liste complète des concepts parents dans la section from , et dans is - alias de seulement ceux d'entre eux qui seront hérités:



concept < > < > is 
	<  >,
from 
	<  > <  > ( 
		< > = <> 
		   ...
	 ),
with < > = <>, ...
without <  >, ...
where < >


La section with vous permet d'agrandir la liste des attributs des concepts hérités ou de remplacer certains d'entre eux, la section sans - pour raccourcir.



L'algorithme d'inférence d'un concept basé sur l'héritage est le même que celui du concept discuté ci-dessus. La seule différence est que la liste des attributs est automatiquement générée sur la base de la liste des attributs du concept parent, et l'expression des relations est complétée par des opérations d'égalité des attributs des concepts enfant et parent.



Considérons plusieurs exemples d'utilisation du mécanisme d'héritage. L'héritage vous permet de créer un concept basé sur un concept existant, en supprimant les attributs qui n'ont de sens que pour le parent, mais pas pour le concept enfant. Par exemple, si les données sources sont présentées sous la forme d'un tableau, les cellules de certaines colonnes peuvent recevoir leur propre nom (en supprimant l'attribut avec le numéro de colonne):



concept revenue is tableCell without columnNum where columnNum = 2


Il est également possible de transformer plusieurs concepts connexes en une seule forme généralisée. La section with est nécessaire pour convertir certains des attributs au format général et ajouter ceux manquants. Par exemple, les données sources peuvent être des documents de différentes versions, dont la liste des champs a changé au fil du temps:



concept resume is resumeV1 with skills = 'N/A'
concept resume is resumeV2 r with skills = r.coreSkills


Disons que la première version du concept "Resume" n'avait pas d'attribut avec des compétences, et la deuxième version avait un nom différent.



L'élargissement de la liste des attributs peut être nécessaire dans de nombreux cas. Les tâches courantes modifient le format des attributs, ajoutent des attributs qui dépendent fonctionnellement d'attributs existants ou de données externes, etc. Par exemple:



concept price is basicPrice with valueUSD = valueEUR * getCurrentRate('USD', 'EUR')


Il est également possible de combiner simplement plusieurs concepts sous un même nom sans changer leur structure. Par exemple, pour indiquer qu'ils appartiennent au même genre:



concept webPageElement is webPageLink
concept webPageElement is webPageInput


Ou créez un sous-ensemble d'un concept en filtrant certaines de ses entités:



concept exceptionalPerformer is employee where performanceEvaluationScore > 0.95


L'héritage multiple est également possible, dans lequel un concept enfant hérite des attributs de tous les concepts parents. S'il existe des noms d'attributs identiques, la priorité sera donnée au concept parent à gauche de la liste. Vous pouvez également résoudre ce conflit manuellement en remplaçant explicitement l'attribut souhaité dans la section with. Par exemple, ce type d'héritage serait pratique si vous avez besoin de rassembler plusieurs concepts associés dans une structure "plate":



concept employeeInfo is employee e, department d where e.departmentId = d.id 


L'héritage sans changer la structure des concepts complique la vérification de l'identité des objets. À titre d'exemple, considérons la définition de ExceptionnelPerformer . Les requêtes sur les concepts parent ( employé ) et enfant ( exceptionnelPerformer ) renverront la même entité employé. Les objets le représentant auront la même signification. Ils auront une source de données commune, la même liste et les mêmes valeurs d'attribut, pour un nom de concept différent, en fonction du concept auquel la requête a été faite. Par conséquent, l'opération d'égalité d'objet doit prendre en compte cette fonctionnalité. Les noms de concept sont considérés comme égaux s'ils coïncident ou sont liés par une relation d'héritage transitive sans changer la structure.



L'héritage est un mécanisme utile pour exprimer explicitement les relations entre des concepts tels que classe-sous-classe, privé-commun et ensemble-sous-ensemble. Et aussi se débarrasser de la duplication du code dans les définitions des concepts et rendre le code plus compréhensible. Le mécanisme d'héritage est basé sur l'ajout / la suppression d'attributs, la combinaison de plusieurs concepts sous un seul nom et l'ajout de conditions de filtrage. Aucune sémantique particulière n'y est intégrée, chacun peut la percevoir et l'appliquer comme il le souhaite. Par exemple, construisez une hiérarchie du particulier au général comme dans les exemples avec les concepts CV , price et webPageElement . Ou, au contraire, du général au spécifique, comme dans les exemples avec les notions de chiffre d' affaires et d' exceptionnel... Cela vous permettra de vous adapter de manière flexible aux spécificités des sources de données.



Concept pour décrire les relations



Il a été décidé que pour faciliter la compréhension du code et faciliter l'intégration du composant de modélisation avec le modèle POO, la relation du concept enfant avec le parent devrait être intégrée dans sa définition. Ainsi, ces relations définissent la manière d'obtenir un concept enfant à partir des concepts parents. Si le modèle de domaine est construit en couches et que chaque nouvelle couche est basée sur la précédente, cela est justifié. Mais dans certains cas, la relation entre les concepts doit être déclarée séparément et ne pas être incluse dans la définition de l'un des concepts. Il peut s'agir d'une relation universelle que vous souhaitez définir en termes généraux et appliquer à différents concepts, par exemple la relation parent-enfant. Soit une relation reliant deux concepts doit être incluse dans la définition des deux concepts, de sorte qu'il soit possible de trouver à la fois l'essence du premier concept avec les attributs connus du second, et vice versa.Ensuite, afin d'éviter la duplication de code, il sera pratique de définir la relation séparément.



Dans la définition d'une relation, il est nécessaire de lister les concepts qui y sont inclus et de définir une expression logique les reliant les uns aux autres:



relation < > 
between <  > <  > (
	< > = <>,
 	 ...	
),
...
where < >


Par exemple, une relation décrivant des rectangles imbriqués peut être définie comme suit:



relation insideSquareRelation between square inner, square outer 
where inner.xLeft > outer.xLeft and inner.xRight < outer.xRight 
and inner.yBottom > outer.yBottom and inner.yUp < outer.yUp


Une telle relation, en fait, est un concept commun, dont les attributs sont les essences de concepts imbriqués:



concept insideSquare (
	inner = i
	outer = o												
) from square i, square o
where i.xLeft > o.xLeft and i.xRight < o.xRight 
and i.yBottom > o.yBottom and i.yUp < o.yUp


La relation peut être utilisée dans les définitions de concept avec d'autres concepts parents. Les concepts inclus dans la relation seront accessibles de l'extérieur et joueront le rôle de ses attributs. Les noms d'attributs correspondent aux alias de concept imbriqués. L'exemple suivant indique que le formulaire HTML inclut les éléments HTML qui se trouvent à l'intérieur sur la page HTML:



oncept htmlFormElement is e 
from htmlForm f, insideSquareRelation(inner = e, outer = f), htmlElement e


Lors de la recherche d'une solution, toutes les valeurs du concept htmlForm seront d'abord trouvées , puis elles seront associées au concept imbriqué à l' extérieur de la relation insideSquare et les valeurs de son attribut interne seront trouvées . À la fin, les valeurs internes liées au concept de htmlElement seront filtrées .



La relation peut également recevoir une sémantique fonctionnelle - elle peut être utilisée en tant que fonction d'un type booléen pour vérifier si la relation est satisfaite pour les entités de concept imbriquées données:



oncept htmlFormElement is e 
from htmlElement e, htmlForm f
where  insideSquareRelation(e, f)


Contrairement au cas précédent, ici la relation est traitée comme une fonction, ce qui affectera l'ordre d'inférence. L'évaluation de la fonction sera différée jusqu'au moment où tous ses arguments seront associés à des valeurs. Autrement dit, toutes les combinaisons de valeurs des concepts htmlElement et htmlForm seront d'abord trouvées , puis celles qui ne correspondent pas à la relation insideSquareRelation seront filtrées . J'ai l'intention de parler plus en détail de l'intégration des paradigmes de programmation logiques et fonctionnels dans l'une des prochaines publications.



Il est maintenant temps de regarder un petit exemple.



Les définitions des faits et les types de concepts de base suffisent pour mettre en œuvre l'exemple avec les débiteurs dès la première publication. Supposons que nous ayons deux fichiers CSV stockant les informations client (ID client, nom et adresse e-mail) et les factures (ID de compte, ID client, date, montant dû, montant payé).



Et il existe également une certaine procédure qui lit le contenu de ces fichiers et les convertit en un ensemble de faits:



fact cell {
	table: “TableClients”,
	value: 1,
	rowNum: 1,
	columnNum: 1
};
fact cell {
	table: “TableClients”,
	value: “John”,
	rowNum: 1,
	columnNum: 2
};
fact cell {
	table: “TableClients”,
	value: “john@somewhere.net”,
	rowNum: 1,
	columnNum: 3
};
fact cell {
	table: “TableBills”,
	value: 1,
	rowNum: 1,
	columnNum: 1
};
fact cell {
	table: “TableBills”,
	value: 1,
	rowNum: 1,
	columnNum: 2
};
fact cell {
	table: “TableBills”,
	value: 2020-01-01,
	rowNum: 1,
	columnNum: 3
};
fact cell {
	table: “TableBills”,
	value: 100,
	rowNum: 1,
	columnNum: 4
};
fact cell {
	table: “TableBills”,
	value: 50,
	rowNum: 1,
	columnNum: 5
};


Tout d'abord, donnons aux cellules du tableau des noms significatifs:



concept clientId is cell where table = “TableClients” and columnNum = 1;
concept clientName is cell where table = “TableClients” and columnNum = 2;
concept clientEmail is cell where table = “TableClients” and columnNum = 3;
concept billId is cell where table = “TableBills” and columnNum = 1;
concept billClientId is cell where table = “TableBills” and columnNum = 2;
concept billDate is cell where table = “TableBills” and columnNum = 3;
concept billAmountToPay is cell where table = “TableBills” and columnNum = 4;
concept billAmountPaid is cell where table = “TableBills” and columnNum = 5;


Vous pouvez maintenant combiner des cellules d'une ligne en un seul objet:



concept client (
	id = id.value,
	name = name.value,
	email = email.value
) from clientId id, clientName name, clientEmail email
where id.rowNum = name.rowNum = email.rowNum;


concept bill (
	id = id.value,
	clientId = clientId.value,
	date = date.value,
	amountToPay = toPay.value,
	amountPaid = paid.value
) from billId id, billClientId clientId, billDate date, billAmountToPay  toPay,  billAmountPaid  paid
where id.rowNum = clientId.rowNum = date.rowNum = toPay.rowNum = paid.rowNum;


Introduisons les concepts "Facture impayée" et "Débiteur":



concept unpaidBill is bill where amountToPay >  amountPaid;
concept debtor is client c where exist(unpaidBill {clientId: c.id});


Les deux définitions utilisent l'héritage, le concept unpaidBill est un sous-ensemble des concepts facture , débiteur - le concept de client . La définition de débiteur contient une sous - requête pour le concept impayé . Nous examinerons en détail le mécanisme des requêtes imbriquées plus loin dans l'une des publications suivantes.



A titre d'exemple de concept «flat», définissons également le concept de «dette client», dans lequel nous combinons certains champs des concepts «client» et «compte»:



concept clientDebt (
	clientName = c.name,
	billDate = b.date,
	debt = b. amountToPay – b.amountPaid
) from unpaidBill b, client c(id = b.client); 


La dépendance entre les attributs des concepts client et bill est déplacée vers la section from , et les dépendances du concept enfant clientDebt - vers la section de ses attributs. Si vous le souhaitez, ils peuvent tous être placés dans la section where - le résultat sera le même. Mais de mon point de vue, la version actuelle est plus concise et met davantage l'accent sur l'objectif de ces dépendances - définir les relations entre les concepts.



Essayons maintenant de définir le concept d'un défaillant malveillant qui a au moins 3 factures impayées d'affilée. Pour ce faire, vous avez besoin d'une relation qui vous permet de commander les factures d'un client par leur date. Une définition générique ressemblerait à ceci:



relation billsOrder between bill next, bill prev
where next.date > prev.date and next.clientId = prev.clientId and not exist(
    bill inBetween 
    where  next.clientId = inBetween.clientId 
    and  next.date > inBetween.date  > prev.date
);


Il précise que deux factures vont de suite si elles appartiennent au même client, la date de l'une est supérieure à la date de l'autre et il n'y a pas d'autre facture entre elles. À ce stade, je ne veux pas m'attarder sur la complexité de calcul d'une telle définition. Mais si, par exemple, nous savons que toutes les factures sont émises avec un intervalle de 1 mois, cela peut être grandement simplifié:



relation billsOrder between bill next, bill prev
where next.date = prev.date + 1 month and next.clientId = prev.clientId;


La séquence de 3 factures impayées ressemblera à ceci:



concept unpaidBillsSequence (clientId = b1.clientId, bill1 = b1, bill2 = b2, bill3 = b3) 
from 
    unpaidBill b1, 
    billsOrder next1 (next = b1, prev = b2)
    unpaidBill b2
    billsOrder next2 (next = b2, prev = b3)
    unpaidBill b3;


Dans ce concept, toutes les factures impayées seront d'abord trouvées, puis pour chacune d'elles la facture suivante sera trouvée en utilisant la relation suivant1 . La notion b2 vous permettra de vérifier que cette facture est impayée. Par le même principe, en utilisant next2 et b3 , la troisième facture impayée consécutive sera trouvée. L'identifiant client a été ajouté à la liste des attributs séparément, afin de faciliter davantage la connexion de ce concept avec le concept de clients:



concept hardCoreDefaulter is client c where exist(unpaidBillsSequence{clientId: c.id});


L'exemple de débiteur montre comment un modèle de domaine peut être entièrement décrit dans un style déclaratif. Comparé à l'implémentation de cet exemple en POO ou en style fonctionnel, le code résultant est très concis, compréhensible et proche de la description du problème en langage naturel.



Brèves conclusions.



J'ai donc proposé trois types principaux de concepts du composant de modélisation de langage hybride:



  • concepts créés sur la base de la transformation d'autres concepts;
  • concepts héritant de la structure et des relations d'autres concepts;
  • concepts qui définissent les relations entre d’autres concepts.


Ces trois types de concepts ont des formes et des objectifs différents, mais la logique interne de recherche de solutions est la même pour eux, seule la méthode de formation de la liste d'attributs diffère.



Les définitions de concept ressemblent aux requêtes SQL - à la fois dans la forme et dans la logique interne d'exécution. Par conséquent, j'espère que le langage proposé sera compréhensible pour les développeurs et aura un seuil d'entrée relativement bas. Et des fonctionnalités supplémentaires telles que l'utilisation de concepts dans d'autres définitions de concept, l'héritage, les relations dérivées et les définitions récursives vous permettront d'aller au-delà de SQL et de faciliter la structuration et la réutilisation de votre code.



Contrairement à RDF et OWL, le composant de modélisation ne fait pas la distinction entre les concepts et les relations - tout est des concepts. Contrairement aux langages de la logique de trame, les cadres qui décrivent la structure d'un concept et les règles qui définissent les connexions entre eux sont combinés. Contrairement aux langages de programmation logique traditionnels tels que Prolog, l'élément principal du modèle est constitué de concepts qui ont une structure orientée objet, et non de règles qui ont une structure plate. Cette conception de langage n'est peut-être pas aussi pratique pour créer des ontologies à grande échelle ou un ensemble de règles, mais elle est bien meilleure pour travailler avec des données semi-structurées et pour intégrer des sources de données disparates. Les concepts du composant de modélisation sont proches des classes du modèle POO, ce qui devrait faciliter la tâche d'inclure une description déclarative du modèle dans le code d'application.



La description du composant de modélisation n'est pas encore terminée. Dans le prochain article, je prévois de discuter de ces problèmes du monde de la logique informatique en tant que variables booléennes, négation et éléments de logique d'ordre supérieur. Et après cela, des définitions imbriquées de concepts, d'agrégations et de concepts qui génèrent leurs entités à l'aide d'une fonction donnée.



Le texte intégral en style scientifique en anglais est disponible à l' adresse : papers.ssrn.com/sol3/papers.cfm?abstract_id=3555711



Liens vers les publications précédentes:



Conception d'un langage de programmation multi-paradigme. Partie 1 - À quoi ça sert?

Nous concevons un langage de programmation multi-paradigme. Partie 2 - Comparaison de la construction de modèles en PL / SQL, LINQ et GraphQL

Nous concevons un langage de programmation multi-paradigme. Partie 3 - Vue d'ensemble des langages de représentation des connaissances



All Articles