Skip to content

Commit

Permalink
Update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
gilbert committed Apr 1, 2020
1 parent 0668aca commit 4921bf7
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 3 deletions.
89 changes: 86 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,81 @@ You *can* use all these wonder things -- it’s still Ruby after all -- but they

ruby-prolog is written using object-oriented-ish pure Ruby, and should work under all most popular Ruby interpreters. Please report compatibility problems. The core engine is largely based on tiny_prolog, though numerous additional enhancements have been made such as object-oriented refactorings and integration of ideas from the interwebs. Unfortunately I cannot read Japanese and cannot give proper attribution to the original tiny_prolog author. (If *you* can, let me know and I'll update this document!)


Usage
----

Say you want to write the following Prolog code:

```
implication(a, b).
implication(b, c).
implication(c, d).
implies(A, B) :- implication(A, B).
implies(A, B) :- implication(A, Something), implies(Something, B).
```

Here's the equivalent Ruby code using this library:

```rb
db = RubyProlog.new do
implication['a', 'b'].fact
implication['b', 'c'].fact
implication['c', 'd'].fact
implication['c', 'x'].fact

implies[:A, :B] << implication[:A, :B]
implies[:A, :B] << [
implication[:A, :Something],
implies[:Something, :B]
]
end
```

Now you can run some queries:

```rb
# What are all the direct implications of 'c'?
db.query{ implication['c', :X] }
#=> [{ X: 'd' }, { X: 'x' }]

# What are all the things that can directly imply?
db.query{ implication[:X, :_] }
#=> [{ X: 'a' }, { X: 'b' }, { X: 'c' }, { X: 'c' }]

# What are all the things 'a' implies?
db.query{ implies['a', :X] }
#=> [{ X: 'b' }, { X: 'c' }, { X: 'd' }, { X: 'x' }]
```

Unfortunately if you have **two** predicates in a query, you can't just use a comma. There two ways to solve this problem:

```rb
# Solution 1: Use an array
db.query{[ implication['b', :S], implies[:S, :B] ]}

# Solution 2: Use a beneign assignment
db.query{_= implication['b', :S], implies[:S, :B] }
```

If you need to add to your database, you can call `instance_eval`:

```rb
db = RubyProlog.new do
implication['a', 'b'].fact
implication['b', 'c'].fact
end

# Later...
db.instance_eval do
implication['c', 'd'].fact
implication['c', 'x'].fact
end
```

This will mutate your database. If you want to "fork" your database instead, you can call `db.clone`, which will return a new instance with all stored data. Cloning like this is optimized to copy as little as possible.

Examples
----

gem install ruby-prolog
Expand All @@ -29,20 +102,30 @@ Two runnable examples are included in the 'bin' directory. The first..

ruby-prolog-hanoi

..is a ruby-prolog solution to the well-known "Towers of Hanoi" problem in computer science. It's not clear, but something Prolog hackers will be interested in. If you have other useful or clever examples, please send a pull request! See the test/ directory for additional examples.
..is a ruby-prolog solution to the well-known "Towers of Hanoi" problem in computer science. It's not clear, but something Prolog hackers will be interested in. If you have other useful or clever examples, please send a pull request!

See the test/ directory for additional examples.

Features
----

* Pure Ruby.
* No wacko dependencies.
* Tested with Ruby 2.0.0!
* Tested with Ruby 2.0.0!
* Object-oriented.
* Multiple Prolog environments can be created and manipulated simultaneously.
* Concurrent access to different core instances should be safe.
* Concurrent access to a single core instance might probably explode in odd ways.

Development
----

```
$ git clone https://github.com/preston/ruby-prolog
$ cd ruby-prolog
$ bundle
$ rake test
```

License
----
Expand Down
27 changes: 27 additions & 0 deletions test/lib/ruby-prolog/ruby-prolog_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,31 @@

_(c.to_prolog.class).must_equal String
end

it 'works on the other examples in the readme' do
db = RubyProlog.new do
implication['a', 'b'].fact
implication['b', 'c'].fact
implication['c', 'd'].fact
implication['c', 'x'].fact

implies[:A, :B] << implication[:A, :B]
implies[:A, :B] << [
implication[:A, :Something],
implies[:Something, :B]
]
end

_( db.query{ implication['c', :X] } ).must_equal [{ X: 'd' }, { X: 'x' }]
_( db.query{ implication[:X, :_] } ).must_equal [{ X: 'a' }, { X: 'b' }, { X: 'c' }, { X: 'c' }]
_( db.query{_= implies['a', :X] } ).must_equal [{ X: 'b' }, { X: 'c' }, { X: 'd' }, { X: 'x' }]

_( db.query{[ implication['b', :S], implies[:S, :B] ]} ).must_equal [{:S=>"c", :B=>"d"}, {:S=>"c", :B=>"x"}]
_( db.query{_= implication['b', :S], implies[:S, :B] } ).must_equal [{:S=>"c", :B=>"d"}, {:S=>"c", :B=>"x"}]

# For good measure
_( db.query{_= implies['a', 'b'] } ).must_equal [{}]
_( db.query{_= implies['a', 'd'] } ).must_equal [{}]
_( db.query{_= implies['a', 'idontexist'] } ).must_equal []
end
end

0 comments on commit 4921bf7

Please sign in to comment.