SLIPS

Esempi Pratici

Hello World

Il classico primo programma in SLIPS:

import SLIPS

let env = CLIPS.createEnvironment()

CLIPS.eval(expr: """
(defrule hello
    =>
    (printout t "Hello, SLIPS!" crlf))
""")

CLIPS.run(limit: nil)

Gestione Fatti

Definizione Template

CLIPS.eval(expr: """
(deftemplate persona
    (slot nome (type STRING))
    (slot età (type INTEGER))
    (slot città (type STRING)))
""")

Assert e Retract

// Assert
let id1 = CLIPS.eval(expr: "(assert (persona (nome \"Mario\") (età 30) (città \"Roma\")))")
let id2 = CLIPS.eval(expr: "(assert (persona (nome \"Luigi\") (età 25) (città \"Milano\")))")

// List facts
CLIPS.eval(expr: "(facts)")

// Retract
CLIPS.eval(expr: "(retract \(id1))")

Regole di Produzione

Pattern Matching Semplice

CLIPS.eval(expr: """
(defrule maggiorenne
    (persona (nome ?n) (età ?e&:(>= ?e 18)))
    =>
    (printout t ?n " è maggiorenne" crlf))
""")

Pattern con Variabili Condivise

CLIPS.eval(expr: """
(defrule stessa-città
    (persona (nome ?n1) (città ?c))
    (persona (nome ?n2&~?n1) (città ?c))
    =>
    (printout t ?n1 " e " ?n2 " vivono a " ?c crlf))
""")

Negazione (NOT)

CLIPS.eval(expr: """
(defrule senza-ordini
    (cliente (id ?id) (nome ?n))
    (not (ordine (cliente-id ?id)))
    =>
    (printout t "Cliente " ?n " senza ordini" crlf))
""")

Sistema Esperto Completo

Sistema per diagnosi medica semplificata:

CLIPS.eval(expr: """
(deftemplate sintomo
    (slot nome)
    (slot gravità (type INTEGER)))

(deftemplate diagnosi
    (slot malattia)
    (slot probabilità (type FLOAT)))

(defrule influenza
    (sintomo (nome febbre) (gravità ?g1&:(> ?g1 7)))
    (sintomo (nome tosse))
    (sintomo (nome mal-di-testa))
    =>
    (assert (diagnosi (malattia influenza) (probabilità 0.85)))
    (printout t "Probabile influenza (85%)" crlf))

(defrule raffreddore
    (sintomo (nome tosse))
    (sintomo (nome naso-chiuso))
    (not (sintomo (nome febbre) (gravità ?g&:(> ?g 7))))
    =>
    (assert (diagnosi (malattia raffreddore) (probabilità 0.75)))
    (printout t "Probabile raffreddore (75%)" crlf))
""")

// Inserimento sintomi
CLIPS.eval(expr: "(assert (sintomo (nome febbre) (gravità 8)))")
CLIPS.eval(expr: "(assert (sintomo (nome tosse) (gravità 6)))")
CLIPS.eval(expr: "(assert (sintomo (nome mal-di-testa) (gravità 5)))")

// Esecuzione
CLIPS.run(limit: nil)

Controllo Flusso

Salience (Priorità)

CLIPS.eval(expr: """
(defrule urgente
    (salience 100)
    (allarme ?tipo)
    =>
    (printout t "URGENTE: " ?tipo crlf))

(defrule normale
    (salience 0)
    (messaggio ?msg)
    =>
    (printout t "Messaggio: " ?msg crlf))
""")

Strategie Agenda

// Depth (default)
CLIPS.eval(expr: "(set-strategy depth)")

// Breadth
CLIPS.eval(expr: "(set-strategy breadth)")

// LEX (Recency)
CLIPS.eval(expr: "(set-strategy lex)")

Funzioni e Calcoli

CLIPS.eval(expr: """
(defrule calcola-sconto
    (ordine (id ?id) (importo ?imp))
    (cliente (id ?cid) (tipo premium))
    =>
    (bind ?sconto (* ?imp 0.20))
    (bind ?finale (- ?imp ?sconto))
    (printout t "Ordine " ?id ": €" ?finale " (sconto €" ?sconto ")" crlf))
""")

Multifield

CLIPS.eval(expr: """
(deftemplate ordine
    (multislot prodotti))

(defrule analizza-ordine
    (ordine (prodotti $?items))
    =>
    (printout t "Numero prodotti: " (length$ $?items) crlf))
""")

Debug e Watch

// Attiva watch facts
CLIPS.eval(expr: "(watch facts)")

// Attiva watch rules
CLIPS.eval(expr: "(watch rules)")

// Output:
// ==> (persona (nome "Mario") (età 30))
// ==> Activation maggiorenne
// FIRE maggiorenne

// Disattiva
CLIPS.eval(expr: "(unwatch facts)")
CLIPS.eval(expr: "(unwatch rules)")

Template Functions 🆕

Modify e Duplicate

// Definisci template
CLIPS.eval(expr: """
(deftemplate person
    (slot name)
    (slot age)
    (slot city))
""")

// Crea fatto
CLIPS.eval(expr: "(assert (person (name \"John\") (age 30) (city \"Rome\")))")
// ==> f-1

// Modifica fatto esistente
CLIPS.eval(expr: "(modify 1 (age 31) (city \"Milan\"))")
// ==> f-2 (nuovo fatto con modifiche)

// Duplica con modifiche
CLIPS.eval(expr: "(duplicate 1 (name \"Jane\"))")
// ==> f-3 (Jane, 31, Milan)

Introspection

// Lista tutti gli slot di un template
CLIPS.eval(expr: "(deftemplate-slot-names person)")
// Output: (create$ name age city)

// Controlla se uno slot è multifield
CLIPS.eval(expr: "(deftemplate-slot-multip person name)")
// Output: FALSE

// Verifica esistenza slot
CLIPS.eval(expr: "(deftemplate-slot-existp person salary)")
// Output: FALSE

Moduli e Focus 🆕

// Definisci moduli
CLIPS.eval(expr: """
(defmodule BILLING
    (export ?ALL))

(defmodule SHIPPING
    (export ?ALL))

(defmodule MAIN
    (import BILLING ?ALL)
    (import SHIPPING ?ALL))
""")

// Definisci regole in moduli diversi
CLIPS.eval(expr: """
(defmodule BILLING)
(defrule calculate-total
    (declare (salience 10))
    (order (amount ?a))
    =>
    (printout t "Total: $" ?a crlf))

(defmodule SHIPPING)
(defrule prepare-shipment
    (order (id ?id))
    =>
    (printout t "Preparing shipment for order " ?id crlf))
""")

// Imposta focus per controllare ordine esecuzione
CLIPS.eval(expr: "(focus BILLING SHIPPING)")

// Run eseguirà prima BILLING, poi SHIPPING
CLIPS.run(limit: nil)

Pattern Avanzati

Test Predicati Complessi

CLIPS.eval(expr: """
(defrule prezzo-sospetto
    (prodotto (nome ?n) (prezzo ?p))
    (test (or (< ?p 0) (> ?p 10000)))
    =>
    (printout t "ALERT: " ?n " ha prezzo anomalo: €" ?p crlf))
""")

Pattern con Wildcard

CLIPS.eval(expr: """
(defrule qualsiasi-età
    (persona (nome ?n) (età ?))
    =>
    (printout t "Trovata persona: " ?n crlf))
""")

Integrazione Swift

Funzioni Custom

import SLIPS

// Registra funzione custom
var env = CLIPS.createEnvironment()
env.functionTable["my-func"] = FunctionDefinitionSwift(name: "my-func") { env, args in
    guard let val = args.first, case .int(let i) = val else {
        return .none
    }
    return .int(i * 2)
}

CLIPS.eval(expr: """
(defrule test
    =>
    (printout t "Risultato: " (my-func 21) crlf))
""")

CLIPS.run(limit: nil)  // Output: Risultato: 42

Router Personalizzati

var logs: [String] = []

Router.AddCallback(&env, name: "custom", priority: 10) { _, _, text in
    logs.append(text)
    return true
}

CLIPS.eval(expr: "(printout custom \"Log message\" crlf)")
print(logs)  // ["Log message\n"]