Friday, March 5, 2010

Recap of Tiny Expert System

Before I move on, let me post a re-do of the the original lazy-evaluated style tiny expert system, incorporating all I've learned about F# over the last couple of weeks. I like this approach. It's a little less sophisticated than the object-oriented versions, but it embodies what I find attractive about F#: simple, direct code that looks like what it does.

(Again, standard disclaimers apply, use at your own risk, etc.)

type Query =
| Yes
| No
| Unknown


let Conjoin q0 q1 =
match q0 with
| Query.No -> Query.No
| Query.Yes -> q1
| _ -> match q1 with
| Query.No -> Query.No
| _ -> Query.Unknown


let Disjoin q0 q1 =
match q0 with
| Query.Yes -> Query.Yes
| Query.No -> q1
| _ -> match q1 with
| Query.Yes -> Query.Yes
| _ -> Query.Unknown


let Negate q0 =
match q0 with
| Query.Yes -> Query.No
| Query.No -> Query.Yes
| _ -> q0


let rec Junction (fc:Query->Query->Query)
(ft:Query->bool)
(lq:Lazy<Query> list) =
match lq with
| [] -> Query.Unknown
| h::[] -> h.Value
| h::t ->
match ft h.Value with
| true -> h.Value
| _ -> fc h.Value
(Junction fc ft t)


let rec Conjunction (lq:Lazy<Query> list) =
Junction Conjoin (fun h->h=Query.No) lq


let rec Disjunction (lq:Lazy<Query> list) =
Junction Disjoin (fun h->h=Query.Yes) lq


let rec All (lq:Lazy<Query> list) =
Junction Disjoin (fun h->false) lq


let rec Not (lq:Lazy<Query>) = lazy (
Negate lq.Value)


let rec internal GetQuery q =
printf "%s (y/n/u) " q
let key = Console.ReadKey().KeyChar
printfn ""
match key with
| 'y' | 'Y' -> Query.Yes
| 'n' | 'N' -> Query.No
| 'u' | 'U' -> Query.Unknown
| _ -> GetQuery q


let black = lazy ( GetQuery "Is it black?" )
let orangeColor = lazy ( GetQuery "Is it orange?" )
let white = lazy ( GetQuery "Is it white?" )

let orange = lazy (
Disjunction [
orangeColor;
lazy ( GetQuery "Is it an orange?" )])

let blackAndWhite = lazy (
Conjunction [
black;
white])

let blackAndOrange = lazy (
Conjunction [
black;
orange])

let blackAndWhiteAndOrange = lazy (
Conjunction [
black;
white;
orange])

let blackAndWhiteOnly = lazy (
Conjunction [
blackAndWhite;
(Not orange)])

let blackAndOrangeOnly = lazy (
Conjunction [
blackAndOrange;
(Not white)])

let color = lazy (
All [
blackAndWhite;
blackAndOrange;
blackAndWhiteAndOrange;
blackAndWhiteOnly;
blackAndOrangeOnly])


color.Value |> ignore


No comments: