<commit_before>= Rubylog - Prolog interpreter for ruby

Rubylog is a Prolog-like DSL for Ruby. The language is inspired by {Jamis
Buck}[http://weblog.jamisbuck.org/2006/10/28/prolog-in-ruby], and the
implementation is based on {Yield Prolog}[http://yieldprolog.sourceforge.net/],
with lots of sintactic and semantic additions.

== Getting started

First, install the gem

  $ gem install rubylog

or, if you use +bundler+, add this file to your +Gemfile+:

  gem 'rubylog', '~>1.0.0'



First, you have to create a theory and write your code in the block given to it:

  require 'rubylog'

  MyTheory = theory do
    # your code here
  end

All further examples in this file should be written within the +theory+ block.

=== Data types

Rubylog is similar to Prolog, but there are quite a few differences. In Rubylog, you can use any Ruby object as a term (you can assign them to variables, for example). You just have to declare it as a +subject+:

  subject String

==== Structures

In Prolog, the main (and the only) complex data type is the structure (+likes('John', 'beer')+). In Rubylog, we also have Rubylog::Structure. The syntax for structures, however is different: the first argument comes first, then the functor, and then the rest of the arguments. Technically, it's a method call: 

  p 'John'.likes('beer')       # write(likes(john,beer)) in Prolog

But you have to declare any functor before using it:

  functor :likes, :drinks, :has, :good

Or, you can enter implicit mode while you start using new functors. Then your functors will be declared automatically:

  implicit
  # your code ...
  implicit false

Make sure you stop implicit mode before running any queries, otherwise strange +TypeError+'s will occur.

==== Lists / Arrays

In Prolog, lists are structures under the hood. In Rubylog however, lists are Ruby +Array+'s, and the relation is vice versa: Structures depend on Arrays, because the list of arguments is an Array.

==== Other composite terms

+Rubylog::Structure+ and +Array+ are just two examples of composite terms. If you want some other kind of composite term, you can implement +Rubylog::CompositeTerm+.


==== Variables

Any non-defined constant within the +theory+ block is treated as a variable. Variables that start with ANY... are treated as don't-care variables.

  A, B, Cat               # the same in Prolog
  ANY, ANYONE, ANYTHING   # _ in Prolog

=== Predicates

The theory object is the core of the Rubylog proving system. It manages the predicates that are known to be true in its database. The database is a two-leveled hash with the functor and the arity as the indices:

  p database[:likes][2]

There are two types of Predicates: Primitives and Procedures. Primitives are those which are implemented in pure Ruby code, Procedures are implemented with asserted clauses.  There is a bunch of built-in predicates, which are mostly Primitives, but not necessarily.

Procedures are created as you assert a new type of clause.

You can assert facts with a bang and rules with +if+:

  'John'.likes! 'milk'                           # likes(john, milk). 
  X.drinks(Y).if X.has(Y).and X.likes(Y)         # drinks(X,Y) :- has(X,Y), likes(X,Y).

Fact assertions return the first argument, so they can be chained:

  'John'.likes!('beer').has!('beer')

You can also assert rules with +unless+:

  A.good.unless A.bad                            # good(A) :- \+(bad(A)).

Nullary predicates are symbols, similar to Prolog:

  'John'.drinks('beer').if :false.and(:cut!).or(:true)



=== Built-in predicates

Some built-in predicates and their Prolog equivalents:

  Rubylog  Prolog
  -------  ------ 
  true     true
  fail     fail
  and      ,
  or       ;
  false    \+
  is       =
  is_not   =/=
  in       member
  cut!     !


=== Unification

In Rubylog, unification works quite the same in Prolog, but with the +is+ functor. One difference is the case of Arrays, where you can use splats:

  [1,2,3,4].is [A,B,*T]      # [1,2,3,4] = [A,B|T]
  [1,2,3,4].is [*H,*T]       # append(H, T, [1,2,3,4])

The +in+ predicate can take any enumerable as the second argument.

=== Moving between Ruby and Rubylog
==== Running a query

If you want to run a query, you have many different syntaxes:

  'John'.drinks? 'beer'         # => true
  ('John'.drinks 'beer').true?  # => true
  true? ('John'.drinks 'beer')  # => true
  prove ('John'.drinks 'beer')  # => true

==== Enumerations

+Structure+ implements +Enumerable+, and yields for each solution, so you can call any Enumerable method on a Structure.

  ('John'.drinks X).each {p X}      # outputs 'beer'
  ('John'.drinks X).map{X}          # => ['beer']
  ('John'.drinks X).count           # => 1

==== Procs as predicates

You can invoke Ruby codes in Rubylog rules with a proc or a block:

  'John'.drinks(Y).if proc { Y.to_s =~ /ale\Z/i } .and { Time.now.hour == 12 }
  'John'.drinks(Y).if { Y.to_s =~ /ale\Z/i }

==== Procs as functions

+is+ and +in+ can take a proc or block argument, which they execute and take its return value:

  X.good.if X.is { 'BEER'.downcase }
  X.good.if X.in { get_good_drinks() }

==== Different modes of Rubylog

Rubylog has two modes, dynamic and static. Any block passed to Rubylog structures (as an enumeration, as a predicate , are executed in dynamic mode.

  ('John'.drinks X).and { X != 'beer'}.each { p X }
  ^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^          static mode
                         ^^^^^^^^^^^^        ^^^^^    dynamic mode

In static mode you usually write structures and assert them or run them as a query. In dynamic mode you write normal Ruby code, and it is executed only when the demonstration runs. Undefined constants in static mode are converted to +Rubylog::Variable+ objects. However, in dynamic mode, they are substituted with the corresponding value of the variable (if any).

All built-in rubylog predicates except for +cut!+ are clean logical programming predicates. That means they have no side-effect when you execute them. If you want some side-effect, you must go into dynamic mode. This means there is an obvious syntactic sign of possible non-cleanness: either the bang or the braces.



== Contributing

=== To the language
* Create an issue on the {issue tracker}[https://github.com/cie/rubylog/issues].
* We will discuss it.
* Maybe I'll introduce it.

=== To the implementation
* Create an issue on the {issue tracker}[https://github.com/cie/rubylog/issues].
* We will discuss it.
* Maybe I'll implement it.
* If not, fork the project.
* Implement it.
* Have fun.
* Post a pull request.

== Copyright

Copyright (c) 2012 <NAME>. See LICENSE.txt for
further details.
<commit_msg>wrote readme<commit_after>= Rubylog - Prolog interpreter for ruby

Rubylog is a Prolog-like DSL for Ruby. The language is inspired by {Jamis
Buck}[http://weblog.jamisbuck.org/2006/10/28/prolog-in-ruby], and the
implementation is based on {Yield Prolog}[http://yieldprolog.sourceforge.net/],
with lots of sintactic and semantic additions.

== Getting started

First, install the gem

  $ gem install rubylog

or, if you use +bundler+, add this line to your +Gemfile+:

  gem 'rubylog', '~>1.0.0'



First, you have to create a theory and write your code in the block given to it:

  require 'rubylog'

  MyTheory = theory do
    # your code here
  end

All further examples in this file should be written within the +theory+ block.


=== Data types

Rubylog is similar to Prolog, but there are quite a few differences. In Rubylog,
you can use any Ruby object as data.

Rubylog variables are (undefined) constant names:

  A, B, ANYTHING

A variables whose name starts with +ANY...+ (case-insensitive) is a don't-care
variable (like +_+ in Prolog).

Structures are in a different order than they are in prolog:

  functor_for String, :likes
  'John'.likes('beer')

which would be +likes('John','beer')+ in prolog.

Lists are just Ruby arrays:

  [1, 2, 3]

They can have splats:

  [1, 2, *T]

Which would be +[1,2|T]+ in Prolog, however, in Rubylog, splats are not limited
to the end.

=== Predicates

You can assert a rule with the +if+ method:

  X.drinks(Y).if X.has(Y).and X.likes(Y)        

This would be +drinks(X,Y) :- has(X,Y), likes(X,Y)+ in Prolog.

You can assert facts with +if(:true)+, or, as a shorthand you can use the bang
syntax:

  'John'.likes! 'milk'                         

Bang assertions return their first argument (which is +'John'+ in this case), so they can be chained:

  'John'.likes!('beer').has!('beer')

You can also use +unless+:

  A.good.unless A.bad              

Nullary predicates are symbols, similar to Prolog:

  'John'.drinks('beer').if :false.and(:cut!).or(:true)



=== Built-in predicates

Some built-in predicates and their Prolog equivalents:

  Rubylog  Prolog
  -------  ------ 
  :true     true
  :fail     fail
  .and      ,
  .or       ;
  :false    \+
  .is       =
  .is_not   =/=
  .in       member
  :cut!     !

There are some new ones:

  is_not, not_in, all, any, one, none, iff

=== Unification

In Rubylog, unification works quite the same in Prolog, with the +is+ functor.

  A.is(B)

Using arrays, you can benefit the splats:

  [1,2,3,4].is([A,B,*T])      # [1,2,3,4] = [A,B|T]     in prolog
  [1,2,3,4].is([*H,*T])       # append(H, T, [1,2,3,4]) in prolog

The +in+ predicate unifies the first argument with any member of the collection:

  4.in([1,2,3,4])

You can use guards:

  A[String].in(["asdf",5,nil]).each { p A }   # outputs "asdf"
  A[/x/].in(["asdf","xyz"]).each { p A }      # outputs "xyz"
  A[thats < 5].in([4,5,6]).each { p A }       # outputs 4

=== Moving between Ruby and Rubylog
==== Running a query

If you want to run a query, you have many different syntaxes:

  prove ('John'.drinks 'beer')  # => true
  true? ('John'.drinks 'beer')  # => true
  ('John'.drinks 'beer').true?  # => true
  'John'.drinks? 'beer'         # => true

==== Enumerations

+Structure+ implements +Enumerable+, and yields the solutions. Within the
enumeration block, you can access the values of your variables.

  'John'.drinks! 'beer'
  ('John'.drinks X).each {p X}      # outputs 'beer'
  ('John'.drinks X).map{X}          # => ['beer']
  ('John'.drinks X).count           # => 1

==== Procs as predicates

You can invoke Ruby codes in Rubylog rules with a proc:

  'John'.likes(Y).if proc{ Y =~ /ale/ }

or in most cases you can use just a block:

  'John'.likes(Y).if { Y =~ /ale/ }

The predicate succeeds if the block returns a true value.

==== Procs as functions

+is+ and +in+ can take a proc or block argument, which they execute and take its return value:

  X.good.if X.is { 'BEER'.downcase }
  X.good.if X.in { get_good_drinks() }

==== The two modes of Rubylog

Rubylog has two modes, DSL and native. DSL code is executed only once
at compile time, and is used for describing the Rubylog program. Native code is
executed runtime. Any block passed to Rubylog structures native code.

  ('John'.drinks X).and { X != 'beer'}.each { p X }
  ^^^^^^^^^^^^^^^^^^^^^^              ^^^^^^          dsl mode
                         ^^^^^^^^^^^^        ^^^^^    native mode

In dsl mode, variables are +Rubylog::Variable+ objects. In native mode,
variables are substituted with their respecitve value (or +nil+ if they are not
bound).

All built-in rubylog predicates are clean logical programming predicates witout
a side-effect. If you want some side-effect, you always go into native mode.

=== Rubylog as a test suite

You can write simple tests using the +check+ method:

  theory do
    check :true
    check { 5+5 == 10 }
  end

You sould put this file in +"./logic/something\_logic.rb"+. Then you can run it
with 

  rubylog logic/something_logic.rb

Or you can run all files in +logic/**/*_logic.rb+ with

  rubylog

=== Other built-in libraries

==== File system

You can make some queries on the file system:

  require "rubylog/builtins/file_system"

  theory do
    check "README".filename_in "."

    X.dirname_in(".").each { puts X }
  end


==== Reflection

You can make some metaprogramming with Rubylog


  require "rubylog/builtins/reflection"

  theory do
    functor_for String, :likes

    check "John".likes("Jane").structure(:likes, ["John", "Jane"])

    "John".likes(X).if X.likes("John")
    "Jane".likes!("John")
    check "John".likes("Jane").follows_from "Jane".likes("John")

    "John".likes!("milk")
    check "John".likes("milk").fact
    check "John".likes("beer").fact.false

  end

== Contributing

=== To the language
* Create an issue on the {issue tracker}[https://github.com/cie/rubylog/issues].
* We will discuss it.
* Maybe I'll introduce it.

=== To the implementation
* Create an issue on the {issue tracker}[https://github.com/cie/rubylog/issues].
* We will discuss it.
* Maybe I'll implement it.
* If not, fork the project.
* Implement it.
* Have fun.
* Post a pull request.

== Copyright

Copyright (c) 2013 <NAME>. See LICENSE.txt for
further details.

{'fraction_non_alphanumeric': 0.12091225357557016, 'fraction_numerical': 0.006880556629300348, 'mean_word_length': 3.1918340894361634, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 19, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2580826', 'n_tokens_mistral': 4277, 'n_tokens_neox': 4057, 'n_words': 1656}