SHOW:
|
|
- or go back to the newest paste.
1 | %% Backward chaining | |
2 | ||
3 | -module(backward). | |
4 | -export([start/0,mainLoop/0,solveGoal/2,solveRule/2,collect/3]). | |
5 | ||
6 | start() -> | |
7 | %% Initialize KB | |
8 | ets:new(rules, [bag, named_table]), | |
9 | ets:insert(rules, {g,[d,e,f,h,i,j],1.0}), | |
10 | ets:insert(rules, {g,[a,b,c],1.1}), | |
11 | ets:insert(rules, {a,[],0.1}), | |
12 | ets:insert(rules, {b,[],0.2}), | |
13 | ets:insert(rules, {c,[],0.3}), | |
14 | ets:insert(rules, {d,[],0.4}), | |
15 | ets:insert(rules, {e,[],0.5}), | |
16 | ets:insert(rules, {f,[],0.6}), | |
17 | ets:insert(rules, {h,[],0.7}), | |
18 | ets:insert(rules, {i,[],0.8}), | |
19 | ets:insert(rules, {j,[],0.9}), | |
20 | mainLoop(). | |
21 | ||
22 | mainLoop() -> | |
23 | Query = io:read("Enter query: "), | |
24 | - | solveGoal(element(2, Query), self()), |
24 | + | if |
25 | Query == {ok, x} -> exit(normal); | |
26 | - | {_, Truth} -> io:format("Answer is: ~w~n", [Truth]) |
26 | + | true -> ok |
27 | end, | |
28 | Daddy = spawn(backward, solveGoal, [element(2, Query), self()]), | |
29 | receive | |
30 | {_, Truth} -> io:format("Answer is: ~w~n", [Truth]), | |
31 | exit(Daddy, ok) | |
32 | end, | |
33 | mainLoop(). | |
34 | ||
35 | solveGoal(Goal, Caller) -> | |
36 | %% Fetch rules... | |
37 | ApplicableRules = ets:match(rules,{Goal, '$1', '$2'}), | |
38 | lists:foreach( | |
39 | - | true -> spawn(backward, solveRule, [RuleBody, self()]) |
39 | + | |
40 | if | |
41 | %% If RHS is null | |
42 | RuleBody == [] -> Caller ! {Goal, Truth}; | |
43 | %% If RHS contains subgoals | |
44 | true -> spawn_link(backward, solveRule, [RuleBody, self()]) | |
45 | - | {_, Truth} -> Caller ! {Goal, Truth} |
45 | + | |
46 | ApplicableRules), | |
47 | receive | |
48 | %% Each message is of the form {goal,truth} | |
49 | %% Just accept the 1st answer | |
50 | - | Collector = spawn(backward, collect, [[], N, Caller]), |
50 | + | {_, Truth} -> Caller ! {Goal, Truth} |
51 | end. | |
52 | ||
53 | solveRule(RuleTail, Caller) -> | |
54 | - | fun(Subgoal) -> spawn(backward, solveGoal, [Subgoal, Collector]) end, |
54 | + | |
55 | Collector = spawn_link(backward, collect, [[], N, Caller]), | |
56 | %% For each subgoal in Rule | |
57 | %% Spawn a process to solve each subgoal | |
58 | lists:foreach( | |
59 | fun(Subgoal) -> spawn_link(backward, solveGoal, [Subgoal, Collector]) end, | |
60 | RuleTail). | |
61 | - | if length(Truths) == N -> Caller ! {dont_care, lists:min(Truths)}; |
61 | + | |
62 | %% Accumulate results | |
63 | collect(Truths, N, Caller) -> | |
64 | %% If we have N messages send back the answer | |
65 | %% Answer = min of truth values, equivalent to fuzzy-logic AND | |
66 | if length(Truths) == N -> Caller ! {dont_care, lists:sum(Truths)}; | |
67 | true -> true | |
68 | end, | |
69 | receive | |
70 | {_, Truth} -> collect([Truth | Truths], N, Caller) | |
71 | end. |