Esempi Pratici
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)
CLIPS.eval(expr: """
(deftemplate persona
(slot nome (type STRING))
(slot età (type INTEGER))
(slot città (type STRING)))
""")
// 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))")
CLIPS.eval(expr: """
(defrule maggiorenne
(persona (nome ?n) (età ?e&:(>= ?e 18)))
=>
(printout t ?n " è maggiorenne" crlf))
""")
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))
""")
CLIPS.eval(expr: """
(defrule senza-ordini
(cliente (id ?id) (nome ?n))
(not (ordine (cliente-id ?id)))
=>
(printout t "Cliente " ?n " senza ordini" crlf))
""")
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)
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))
""")
// Depth (default)
CLIPS.eval(expr: "(set-strategy depth)")
// Breadth
CLIPS.eval(expr: "(set-strategy breadth)")
// LEX (Recency)
CLIPS.eval(expr: "(set-strategy lex)")
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))
""")
CLIPS.eval(expr: """
(deftemplate ordine
(multislot prodotti))
(defrule analizza-ordine
(ordine (prodotti $?items))
=>
(printout t "Numero prodotti: " (length$ $?items) crlf))
""")
// 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)")
// 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)
// 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
// 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)
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))
""")
CLIPS.eval(expr: """
(defrule qualsiasi-età
(persona (nome ?n) (età ?))
=>
(printout t "Trovata persona: " ?n crlf))
""")
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
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"]