Chorus
view release on metacpan or search on metacpan
examples/diagnosis.pl view on Meta::CPAN
package Chorus::Sample::Diagnosis;
use 5.006;
use strict;
use warnings;
our $VERSION = '1.00';
=head1 NAME
Chorus::Sample::Diagnosis - Medical diagnosis illustrating _NEEDED (deep), _LOCK_UNTIL_STABLE, and replay_all()
=head1 DESCRIPTION
A simplified medical diagnosis pipeline with two agents and a patient frame
whose symptom slots are intentionally incomplete.
Patient frame slots
-------------------
temperature : numeric value in °C (may be absent â inferred from skin_temp)
skin_temp : 'hot' | 'normal' | 'cold' (proxy when thermometer unavailable)
cough : 1/0
sore_throat : 1/0
fatigue : 1/0
rash : 1/0
Derived slots (set by the pipeline)
------------------------------------
fever_grade : 'none' | 'low' | 'high' (computed from temperature)
hypothesis : the current diagnostic hypothesis
confidence : 0..1
Mechanisms illustrated:
_NEEDED (2 levels) temperature â infer from skin_temp (backward chaining).
fever_grade â infer from temperature (second _NEEDED level).
_LOCK_UNTIL_STABLE Agent 2 (Diagnose) is blocked while Agent 1 (Collect)
is still making progress.
replay_all() When Diagnose finds a hypothesis that unlocks new
symptom checks, it calls replay_all() so Collect
can complete the missing slots before Diagnose
re-evaluates.
solved() Called when confidence > 0.8.
=cut
use FindBin qw($Bin);
use Chorus::Frame;
use Chorus::Engine;
use Chorus::Expert;
# ---------------------------------------------------------------------------
# Patient â temperature deliberately absent (must be inferred)
# ---------------------------------------------------------------------------
my $patient = Chorus::Frame->new(
id => 'patient-01',
# skin_temp is available; temperature is not â triggers _NEEDED
skin_temp => 'hot',
# temperature intentionally missing
cough => 1,
sore_throat => 1,
fatigue => 1,
rash => 0,
# temperature: inferred from skin_temp via _NEEDED (level 1)
temperature => {
_NEEDED => sub {
my $st = $SELF->skin_temp;
return 39.5 if defined $st && $st eq 'hot';
return 36.6 if defined $st && $st eq 'normal';
return 35.5 if defined $st && $st eq 'cold';
return undef;
},
},
# fever_grade: inferred from temperature via _NEEDED (level 2)
fever_grade => {
_NEEDED => sub {
my $t = $SELF->temperature; # may itself trigger level-1 _NEEDED
return undef unless defined $t;
return 'high' if $t >= 39.0;
return 'low' if $t >= 37.5;
return 'none';
},
},
);
# ---------------------------------------------------------------------------
# Agent 1 â Collect
# Ensures derived slots are materialised on the patient frame.
# Rules load from YAML; each rule sets one derived slot if absent.
# Tagged _LOCK_UNTIL_STABLE: Agent 2 is skipped while this agent succeeds.
# ---------------------------------------------------------------------------
( run in 1.115 second using v1.01-cache-2.11-cpan-800906f7e73 )