Loading rules/rules.go +46 −3 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ package rules import ( "errors" "fmt" "github.com/ichiban/prolog" ) Loading @@ -14,6 +15,9 @@ type Engine struct { var ( prologKinds = ` unit_kind(f, temperature). unit_kind(k, temperature). unit_kind(c, temperature). unit_kind(m2, area). unit_kind(cm2, area). unit_kind(cm, distance). Loading @@ -28,9 +32,22 @@ var ( unit_kind(butter, density). unit_kind(water, density). ` prologKindsConvert = ` convert_kind(mass, volume, density). convert_kind(volume, area, distance). prologConvert = ` rule(GivenQuant, f, TargetQuant, c) :- TargetQuant is (GivenQuant - 32) * 5 / 9. rule(GivenQuant, c, TargetQuant, f) :- TargetQuant is (GivenQuant / 5 * 9) + 32. rule(GivenQuant, c, TargetQuant, k) :- TargetQuant is GivenQuant + 273.15. rule(GivenQuant, k, TargetQuant, c) :- TargetQuant is GivenQuant - 273.15. rule(GivenQuant, GivenUnit, TargetQuant, TargetUnit) :- rule(GivenQuant, GivenUnit, X, Y), rule(X, Y, TargetQuant, TargetUnit). convert(GivenQuant, GivenUnit, TargetQuant, TargetUnit) :- unit_kind(GivenUnit, temperature), unit_kind(TargetUnit, temperature), rule(GivenQuant, GivenUnit, TargetQuant, TargetUnit). ` ) Loading @@ -48,6 +65,10 @@ func New() (*Engine, error) { return nil, err } if err := ngn.p.Exec(prologConvert); err != nil { return nil, err } return ngn, nil } Loading @@ -74,3 +95,25 @@ func (ngn *Engine) Kind(unit string) (string, error) { } return result, nil } // Convert converts units. func (ngn *Engine) Convert(qty float64, givenUnit, targetUnit string) (float64, error) { sols, err := ngn.p.Query("convert(?, ?, Qty, ?).", qty, givenUnit, targetUnit) if err != nil { fmt.Println("Huh?") return 0, err } defer sols.Close() for sols.Next() { var quantity struct { Qty float64 } if err := sols.Scan(&quantity); err != nil { fmt.Println("Scan?") return 0, err } return quantity.Qty, err } return 0, err } rules/rules_test.go +29 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,32 @@ func TestKinds(t *testing.T) { }) } } func TestConverts(t *testing.T) { cases := []struct { name string qty float64 given string target string result float64 }{ { "c to f", 22.0, "c", "f", 71.6, }, } ngn, err := New() assert.NoError(t, err) for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { result, err := ngn.Convert(tc.qty, tc.given, tc.target) assert.NoError(t, err) assert.InDelta(t, tc.result, result, 0.1) }) } } Loading
rules/rules.go +46 −3 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ package rules import ( "errors" "fmt" "github.com/ichiban/prolog" ) Loading @@ -14,6 +15,9 @@ type Engine struct { var ( prologKinds = ` unit_kind(f, temperature). unit_kind(k, temperature). unit_kind(c, temperature). unit_kind(m2, area). unit_kind(cm2, area). unit_kind(cm, distance). Loading @@ -28,9 +32,22 @@ var ( unit_kind(butter, density). unit_kind(water, density). ` prologKindsConvert = ` convert_kind(mass, volume, density). convert_kind(volume, area, distance). prologConvert = ` rule(GivenQuant, f, TargetQuant, c) :- TargetQuant is (GivenQuant - 32) * 5 / 9. rule(GivenQuant, c, TargetQuant, f) :- TargetQuant is (GivenQuant / 5 * 9) + 32. rule(GivenQuant, c, TargetQuant, k) :- TargetQuant is GivenQuant + 273.15. rule(GivenQuant, k, TargetQuant, c) :- TargetQuant is GivenQuant - 273.15. rule(GivenQuant, GivenUnit, TargetQuant, TargetUnit) :- rule(GivenQuant, GivenUnit, X, Y), rule(X, Y, TargetQuant, TargetUnit). convert(GivenQuant, GivenUnit, TargetQuant, TargetUnit) :- unit_kind(GivenUnit, temperature), unit_kind(TargetUnit, temperature), rule(GivenQuant, GivenUnit, TargetQuant, TargetUnit). ` ) Loading @@ -48,6 +65,10 @@ func New() (*Engine, error) { return nil, err } if err := ngn.p.Exec(prologConvert); err != nil { return nil, err } return ngn, nil } Loading @@ -74,3 +95,25 @@ func (ngn *Engine) Kind(unit string) (string, error) { } return result, nil } // Convert converts units. func (ngn *Engine) Convert(qty float64, givenUnit, targetUnit string) (float64, error) { sols, err := ngn.p.Query("convert(?, ?, Qty, ?).", qty, givenUnit, targetUnit) if err != nil { fmt.Println("Huh?") return 0, err } defer sols.Close() for sols.Next() { var quantity struct { Qty float64 } if err := sols.Scan(&quantity); err != nil { fmt.Println("Scan?") return 0, err } return quantity.Qty, err } return 0, err }
rules/rules_test.go +29 −0 Original line number Diff line number Diff line Loading @@ -30,3 +30,32 @@ func TestKinds(t *testing.T) { }) } } func TestConverts(t *testing.T) { cases := []struct { name string qty float64 given string target string result float64 }{ { "c to f", 22.0, "c", "f", 71.6, }, } ngn, err := New() assert.NoError(t, err) for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { result, err := ngn.Convert(tc.qty, tc.given, tc.target) assert.NoError(t, err) assert.InDelta(t, tc.result, result, 0.1) }) } }