Un moteur d'inférence en FORTH

publication: 17 octobre 2026 / mis à jour 17 octobre 2026

Read this page in english

 

Introduction

Un moteur d'inférence est le composant central d'un système expert ou d'une intelligence artificielle symbolique, responsable de la prise de décision et du raisonnement automatisé. Il fonctionne en combinant une base de connaissances (constituée de faits et de règles de production) avec des algorithmes de déduction pour en déduire de nouvelles informations.

Il utilise principalement deux stratégies de raisonnement :

En somme, il simule la logique humaine pour résoudre des problèmes complexes sans nécessiter de programmation procédurale rigide.

L’environnement de développement

Pour le moteur d’inférence, nous utiliserons la version eForth Windows. C’est une version FORTH utilisable pour Windows, disponible ici :
  https://github.com/MPETREMANN11/eForth-Windows/tree/main/__program

eForth ne nécessite aucune installation.

Téléchargez simplement le fichier uEf64-7.0.7.21.exe dans un répertoire, à l’emplacement de votre choix, nommé par exemple eForth.

Ouvrez ce répertoire eForth. Créez un nouveau dossier INFERENCE. Téléchargez les fichiers nécessaires depuis le dépôt logiciel. Vous devriez avoir :

📁 eForth
    uEf64-7.0.7.21.exe
    INFERENCE.fs
    📁 INFERENCE
        config.fs
        facts.fs
        inference-engine.fs
        main.fs
        rules.fs
        tests.fs

Le fichier INFERENCE.FS

C’est le fichier qui permet de se connecter au reste du projet. Contenu :

\ load INFERENCE 
s" INFERENCE/main.fs" included 

A chaque fois que vous voudrez compiler le code et utiliser le moteur d’inférence, il suffira de lancer eForth en cliquant sur le fichier uEf64-7.0.7.21.exe. Une fois eForth démarré, tapez :

include INFERENCE.fs 

Le projet main.fs

L’ensemble du projet est compilé depuis main.fs. Exemple de contenu :

include config.fs               \ load config 
include inference-engine.fs     \ load inference engine 

Vous pouvez rajouter le chargement d’autres fichiers. Par exemple, pour compiler tests.fs :

include config.fs               \ load config 
include inference-engine.fs     \ load inference engine 
include tests.fs 

Les autres fichiers

Ils sont chargés depuis main.fs. Le projet est découpé en fonctionnalités utilisables selon l’évolution du projet. La liste et le contenu des fichiers sources peut évoluer sans préavis et ne plus être ceux décrits dans ce document.

L’ordre de chargement des fichiers est essentiel. Ainsi, on ne peut pas charger le contenu de facts.fs avant d’avoir traité le contenu de inference-engine.fs.

Définir des faits

Vous pensez maîtriser la logique ? C’est parfait. Alors vous savez manipuler les opérateurs logiques ET, OU, NON… Alors voyons un cas pratique avec un exemple tout à fait trivial:

Nous avons deux faits. On peut déduire que s’il pleut et qu’il fait très froid, le risque de gel est réel.

On peut coder ceci en FORTH :

 0 constant FALSE 
-1 constant TRUE 
 
VARIABLE fait-pluie 
VARIABLE fait-froid 
VARIABLE fait-gel 
 
: RAZ-FAITS ( -- ) 
    FALSE fait-pluie ! 
    FALSE fait-froid ! 
    FALSE  fait-gel ! ; 

Nos deux variables fait-pluie et fait-gel sont les drapeaux à tester, avec les valeurs 0 pour faux, -1 pour vrai. Sur ces deux faits, nous pouvons appliquer ces règles:

\ Définition des règles comme des mots Forth standards 
: cond-regle1 ( -- flag ) 
    fait-pluie @  fait-froid @  AND ; 
: act-regle1  ( -- ) 
    cond-regle1 fait-gel ! ; 

A ce stade, nous ne pouvons pas encore parler d’inférence. Et une seule règle, ici act-regle1 ne justifie pas la création d’un moteur d’inférence.

Créer un fait

C’est le premier pas vers un moteur d’inférence. Un fait est une variable qui contient un état logique ou une valeur numérique. Pour définir un fait:

: FACT: ( n|fl comp: --  | exec: -- n ) 
    value 
  ; 

Ce qui nous permet de réécrire les variables ainsi :

FALSE FACT: fait-pluie 
FALSE FACT: fait-froid 
FALSE FACT: fait-gel 

Le mot FACT: crée un fait qui est simplement une valeur. L’exécution d’un fait empile sa valeur:

21 FACT: temperature 
temperature   \ empile 21 

Autodocumenter un fait

L’idée est de greffer une chaîne de caractères qui informe sur la nature du contenu du fait déclaré. EForth sait gérer les chaînes terminées par zéro :

z" Température extérieure" z>s type  \ affiche le texte :  Température extérieure 

Pour greffer ce type de chaîne à un fait, on va simplement compiler l’adresse de cette chaîne après la valeur:

: FACT: ( n|fl comp: --  | exec: -- n ) 
    value                   \ create value 
    ,                       \ compile pointer to zstring 
  ; 

Et s’utilise comme ceci:

z" Température extérieure" 21 FACT: ext-temp 

L’exécution de ext-temp empile la valeur 21.

Pour récupérer la chaîne de caractères compilée après cette valeur, il faut explorer le champ de données de ext-temp:

' ext-temp >body cell + @ z>s cr type 
\ affiche: Température extérieure 

Pour faciliter l’accès aux données dans le champ de données d’un fait créé par FACT:, on définit cette structure:

structures 
struct __FACTS 
    ptr field ->value       \ fact value 
    ptr field ->zstring     \ point to zstring 
forth 

Pour connaître le statut d’un fait, on va définir ce mot:

\ display zstring and value in fact 
\ example: '  explain-fact 
: explain-fact { xtAddr -- } 
    xtAddr >name type 
    xtAddr >body ->zstring @ z>s cr  4 spaces type ."  = "  
    xtAddr >body ->value @ { valfact } 
    valfact 0= if 
        ." FALSE" exit 
    then 
    valfact -1 = if 
        ." TRUE" exit 
    then 
    valfact . 
  ; 

Et s’utilise ainsi:

' ext-temp explain-fact   \ display: 
\ ext-temp 
\     Température = 21 

Création et gestion du vocabulaire facts

En l’état, tous les faits sont définis dans le vocabulaire FORTH. Si on mixe des définitions classiques, des règles, des faits, l’exécution de vlist va restituer une liste de mots difficile à gérer. L’idée serait donc de définir tous les faits et seulement ces faits dans un vocabulaire spécifique:

vocabulary facts    \ new facts defined in this vocabulary 

Pour basculer une création de faits dans ce vocabulaire, on définit des sélecteurs de vocabulaires:

: in-facts ( -- ) 
    facts definitions 
  ; 
 
: in-forth ( -- ) 
    only  
    forth definitions 
  ; 

Ces sélecteurs sont incorporés à la définition de FACTS: :

\ create a new fact 
: FACT: ( n|fl comp: --  | exec: -- n ) 
    in-facts 
    value                   \ create value 
    ,                       \ compile pointer to zstring 
    in-forth 
  ; 

Définissons ces faits :

z" Pleut-il" FALSE   FACT: fait-pluie 
z" Température extérieur" -4   FACT: ext-temp 
z" Gèle-t-il" FALSE  FACT: fait-gel 

Ces faits seront définis dans le vocabulaire facts et sont visibles:

facts vlist    \ affiche: fait-gel ext-temp fait-pluie 

Listage des faits

L’idée sous-jacente de gestion des faits dans le vocabulaire facts, c’est de permettre ensuite le listage détaillé. Pour ce faire, on définit ce mot:

forth definitions also internals 
: list-facts ( -- ) 
    facts context @ @ 
    begin  dup nonvoc?  
    while  dup explain-fact cr cr >link  
    repeat  
    drop 
    forth 
  ; 
only 

L’exécution de list-facts sélectionne le vocabulaire facts et récupère le code exécutable de chaque fait. Ce code exécutable est exploité par explain-fact. Résultat:

list-facts    \ display: 
\ fait-gel 
\     Gèle-t-il = FALSE 
\  
\ ext-temp 
\     Température = -4 
\  
\ fait-pluie 
\     Pleut-il = FALSE 

Cette liste de faits affiche les faits et sur la ligne suivante l’auto-documentation et la valeur du fait. Le mot list-facts permet donc de tracer tous les faits traités par le moteur d’inférence.

Remise à zéro des faits

La manière dont les faits sont listés est exploitée pour remettre à FALSE tous les faits:

\ reset fact value to FALSE 
: (reset-fact) ( xt -- ) 
    >body FALSE swap ! 
  ; 
 
\ reset values of all facts defined in facts vocabulary 
forth definitions also internals 
: reset-facts ( -- ) 
    facts context @ @ 
    begin  dup nonvoc?  
    while  dup (reset-fact) >link  
    repeat  
    drop cr ." All facts set to FALSE" 
    forth 
  ; 
only 

Le mot reset-facts analyse chaque fait déclaré dans le vocabulaire facts et remet sa valeur à FALSE.

Affectation d’une valeur à un fait

Dans le fichier vocForthExtensions.fs se trouve le mot val-input:

\ wait a value and push it on stack 
: val-input ( -- n ) 
    PAD 80 ACCEPT 
    PAD SWAP 
    EVALUATE 
  ; 

Le contenu du fichier vocForthExtensions.fs est compilé par main.fs avant la compilation du moteur d’inférence. Le mot val-input attend la saisie d’une valeur numérique depuis le clavier et empile sa valeur. Utilisation:

facts 
cr ." Température actuelle: " val-input to ext-temp  \ saisir 27 
ext-temp ,   \ affiche 27 

A noter que vous pouvez également saisir TRUE ou FALSE, car val-input effectue une évaluation de la valeur saisie. Si cette valeur est une constante ou valeur du vocabulaire FORTH, ce mot sera exécuté et sa valeur déposée sur la pile de données.

Définir des règles

Les règles traitent les faits en deux étapes:

  1. vérifie un ou plusieurs faits ;
  2. traite un ou plusieurs faits si la règle est vérifiée

Exemple:

FALSE value F1 
FALSE value F2 
FALSE value F3 
: R1  ( -- )   \ our first rule 
    F1 F2 and if 
        TRUE to F3 
    then ; 

Rien de bien compliqué. Factorisons la partie condition et la partie action:

: condition-R1 ( -- fl ) 
    F1 F2 and ; 
: action-R1 ( -- ) 
    TRUE to F3 ; 
: R1  ( -- )   \ our first rule 
    condition-R1 if 
        action-R1 
    then ; 

Legal: site web personnel sans commerce / personal site without seling