What is this?
ichiban/prolog
is an embeddable scripting language for Go.
Unlike any other scripting engines, ichiban/prolog
implements logic programming language Prolog.
- Easy to reason about: based on first-order logic
- Easy to adopt:
database/sql
-like Go API - Intelligent: full-featured Prolog implementation
- Highly customizable: sandboxing, custom predicates
ichiban/prolog
vs otto vs go-lua
prolog | otto | go-lua | |
---|---|---|---|
Language | ISO Prolog | ECMA Script | Lua |
Paradigm | Object-oriented | Object-oriented | |
Go API | database/sql -like |
original | original |
Declarative | |||
Sandboxing |
Getting started
Install latest version
go get -u github.com/ichiban/prolog
Usage
Instantiate an interpreter
p := prolog.New(os.Stdin, os.Stdout) // Or `prolog.New(nil, nil)` if you don't need user_input/user_output.
Or, if you want a sandbox interpreter without any built-in predicates:
// See examples/sandboxing/main.go for details.
p := new(prolog.Interpreter)
Load a Prolog program
if err := p.Exec(`
human(socrates). % This is a fact.
mortal(X) :- human(X). % This is a rule.
`); err != nil {
panic(err)
}
Similar to database/sql
, you can use placeholder ?
to insert Go data as Prolog data.
if err := p.Exec(`human(?).`, "socrates"); err != nil { // Same as p.Exec(`human(socrates).`)
panic(err)
}
Run the Prolog program
sols, err := p.Query(`mortal(?).`, "socrates") // Same as p.Query(`mortal(socrates).`)
if err != nil {
panic(err)
}
defer sols.Close()
// Iterates over solutions.
for sols.Next() {
fmt.Printf("Yes.\n") // ==> Yes.
}
// Check if an error occurred while querying.
if err := sols.Err(); err != nil {
panic(err)
}
Or, if you want to query for the variable values for each solution:
sols, err := p.Query(`mortal(Who).`)
if err != nil {
panic(err)
}
defer sols.Close()
// Iterates over solutions.
for sols.Next() {
// Prepare a struct with fields which name corresponds with a variable in the query.
var s struct {
Who string
}
if err := sols.Scan(&s); err != nil {
panic(err)
}
fmt.Printf("Who = %s\n", s.Who) // ==> Who = socrates
}
// Check if an error occurred while querying.
if err := sols.Err(); err != nil {
panic(err)
}
The Default Language
Top Level
1pl
is an experimental top level command for testing the default language and its compliance to the ISO standard.
You can install it with go install
:
go install github.com/ichiban/prolog/cmd/1pl@latest
Then, you can enter the top level with 1pl
:
$(go env GOPATH)/bin/1pl [<file>...]
Directives
:- dynamic(PI)
Specifies the predicates indicated byPI
are dynamic. ISO:- multifile(PI)
Not supported yet. ISO:- discontiguous(PI)
Not supported yet. ISO:- op(Priority, Specifier, Op)
Alters the operator table. ISO:- char_conversion(In, Out)
Alters the character conversion mapping. ISO:- initialization(T)
Not supported yet. ISO:- include(F)
Not supported yet. ISO:- ensure_loaded(P)
Not supported yet. ISO:- set_prolog_flag(Flag, Value)
Alters the value for the Prolog flag. ISO:- built_in(PI)
Specifies the predicates indicated byPI
are built-in.
Predicates
Control constructs
true
Always succeeds. ISOfail
Always fails. ISOcall(Goal)
CallsGoal
. ISO!
Cut. ISOP, Q
Conjunction. ISOP; Q
Disjunction. ISOIf -> Then
If-then. ISOIf -> Then; Else
If-then-else. ISOcatch(Goal, Catcher, Recovery)
CallsGoal
. If an exception is raised and unifies withCatcher
, callsRecovery
. ISOthrow(Ball)
Raises an exceptionBall
. ISO
Term unification
X = Y
UnifiesX
withY
. ISOunify_with_occurs_check(X, Y)
UnifiesX
withY
with occurs check. ISOX \= Y
Succeeds iffX
andY
are not unifiable. ISOsubsumes_term(General, Specific)
Succeeds iff there's a substitutionθ
such thatGeneralθ = Specificθ
andSpecificθ = Specific
. ISO
Type testing
var(X)
Succeeds iffX
is a variable. ISOatom(X)
Succeeds iffX
is an atom. ISOinteger(X)
Succeeds iffX
is an integer. ISOfloat(X)
Succeeds iffX
is a float. ISOatomic(X)
Succeeds iffX
is neither a variable nor a compound. ISOcompound(X)
Succeeds iffX
is a compound. ISOnonvar(X)
Succeeds iffX
is not a variable. ISOnumber(X)
Succeeds iffX
is either an integer or a float. ISOcallable(X)
Succeeds iffX
is either an atom or a compound. ISOground(X)
Succeeds iffX
is a ground term. ISOacyclic_term(X)
Succeeds iffX
is acyclic. ISO
Term comparison
X @=< Y
EitherX == Y
orX @< Y
. ISOX == Y
Equivalent tocompare(=, X, Y)
. ISOX \== Y
Equivalent to\+compare(=, X, Y)
. ISOX @< Y
Equivalent tocompare(<, X, Y)
. ISOX @> Y
Equivalent tocompare(>, X, Y)
. ISOX @>= Y
EitherX == Y
orX @> Y
. ISOcompare(Order, X, Y)
ComparesX
andY
and unifiesOrder
with either<
,=
, or>
. ISOsort(List, Sorted)
Succeeds iffSorted
unifies with a sorted list ofList
. ISOkeysort(Pairs, Sorted)
Succeeds iffPairs
is a list ofKey-Value
pairs andSorted
unifies with a permutation ofPairs
sorted byKey
. ISO
Term creation and decomposition
functor(Term, Name, Arity)
Succeeds iffTerm
ia either a compound term ofName
andArity
or an atom ofName
andArity = 0
. ISOarg(N, Term, Arg)
Succeeds iffArg
is theN
-th argument ofTerm
. ISOTerm =.. List
Succeeds iffList
is a list of the functor and arguments ofTerm
. ISOcopy_term(Term1, Term2)
Creates a copy ofTerm1
and unifies it withTerm2
. ISOterm_variables(Term, Vars)
Succeeds iffVars
is a list of variables appear inTerm
. ISO
Arithmetic evaluation
Result is Expression
EvaluatesExpression
and unifies it withResult
. ISOExpression
is either:-
integer,
-
float, or
-
evaluable functors
X + Y
X - Y
X * Y
X // Y
X / Y
X rem Y
X mod Y
-X
abs(X)
sign(X)
float_integer_part(X)
float_fractional_part(X)
float(X)
floor(X)
truncate(X)
round(X)
ceiling(X)
+(X)
X div Y
X ** Y
sin(X)
cos(X)
atan(X)
exp(X)
log(X)
sqrt(X)
max(X, Y)
min(X, Y)
X ^ Y
asin(X)
acos(X)
atan2(X, Y)
tan(X)
pi
X >> Y
X << Y
X /\ Y
X \/ Y
\X
xor(X, Y)
-
succ(X, S)
Succeeds iffS
is the successor of the non-negative integerX
. prologue
Arithmetic comparison
E1 =:= E2
Succeeds iffE1
andE2
are evaluated toEV1
andEV2
respectively andEV1
equals toEV2
. ISOE1 =\= E2
Succeeds iffE1
andE2
are evaluated toEV1
andEV2
respectively andEV1
does not equal toEV2
. ISOE1 < E2
Succeeds iffE1
andE2
are evaluated toEV1
andEV2
respectively andEV1
is greater thanEV2
. ISOE1 =< E2
Succeeds iffE1
andE2
are evaluated toEV1
andEV2
respectively andEV1
is greater than or equal toEV2
. ISOE1 > E2
Succeeds iffE1
andE2
are evaluated toEV1
andEV2
respectively andEV1
is less thanEV2
. ISOE1 >= E2
Succeeds iffE1
andE2
are evaluated toEV1
andEV2
respectively andEV1
is less than or equal toEV2
. ISO
Clause retrieval and information
clause(Head, Body)
Succeeds iffHead :- Body
unifies with a clause in the DB. ISOcurrent_predicate(PI)
Succeeds iff the predicate indicated byPI
is in the DB. ISO
Clause creation and destruction
asserta(Clause)
PrependsClause
to the DB. ISOassertz(Clause)
AppendsClause
to the DB. ISOretract(Clause)
Removes a clause that unifies withClause
from the DB. ISOabolish(PI)
Removes the predicate indicated byPI
from the DB. ISOretractall(Head)
Removes all the clauses which head unifies withHead
from the DB. ISO
All solutions
findall(Template, Goal, Instances)
Succeeds iffInstances
unifies with a list ofTemplate
for each solution ofGoal
. ISObagof(Template, Goal, Instances)
Succeeds iffInstances
unifies with a bag (multiset) ofTemplate
for each solution ofGoal
. ISOsetof(Template, Goal, Instances)
Succeeds iffInstances
unifies with a set ofTemplate
for each solution ofGoal
. ISO
Stream selection and control
current_input(Stream)
Succeeds iffStream
unifies with the current input stream. ISOcurrent_output(Stream)
Succeeds iffStream
unifies with the current output stream. ISOset_input(S_or_a)
Sets the current input stream to the stream indicated byS_or_a
which is either the stream itself or its alias. ISOset_output(S_or_a)
Sets the current output stream to the stream indicated byS_or_a
which is either the stream itself or its alias. ISOopen(File, Mode, Stream, Options)
Opens the fileFile
inMode
withOptions
and unifies the stream withStream
. ISOMode
is either:read
,write
, orappend
.Options
is a list of stream options listed below:type(T)
Specifies the type of the stream.T
is eithertext
(default) orbinary
.reposition(Bool)
Specifies if the stream can be repositions.Bool
is eithertrue
orfalse
.alias(A)
Specifies the alias for the stream.A
is an atom.eof_action(Action)
Specifies the action that will be taken when the input stream reached to the end.Action
is either:error
which throws an exception,eof_code
which returns a value indicating the end of stream (default), orreset
which resets the stream.
open(File, Mode, Stream)
Equivalent toopen(File, Mode, Stream, [])
. ISOclose(S_or_a, Options)
Closes the stream indicated byS_or_a
which is the stream itself or its alias. ISOOptions
is a list of:force(Bool)
Specifies if an exception will be raised when it failed to close the stream.Bool
is eitherfalse
(default) ortrue
.
close(S_or_a)
Equivalent toclose(S_or_a, [])
. ISOflush_output(S_or_a)
Sends any buffered output to the stream indicated byS_or_a
which is either the stream itself or its alias. ISOflush_output
Equivalent tocurrent_output(S), flush_output(S)
. ISOstream_property(Stream, Property)
Succeeds iff the streamStream
has the propertyProperty
. ISOProperty
is either:file_name(F)
mode(M)
input
output
alias(A)
position(P)
end_of_stream(E)
eof_action(A)
reposition(Bool)
type(T)
at_end_of_stream
Equivalent tocurrent_input(S), at_end_of_stream(S)
. ISOat_end_of_stream(S_or_a)
Succeeds iff the stream indicated byS_or_a
which is either a stream or an alias has the property eitherend_of_stream(at)
orend_of_stream(past)
. ISOset_stream_position(S_or_a, Position)
Sets the position of the stream indicated byS_or_a
which is either a stream or an alias to the positionPosition
. ISO
Character input/output
get_char(S_or_a, Char)
Succeeds iffChar
unifies with the next character from the stream indicated byS_or_a
which is either a stream or an alias. ISOget_char(Char)
Equivalent tocurrent_input(S), get_char(S, Char)
. ISOget_code(S_or_a, Code)
Succeeds iffChar
unifies with the next code from the stream indicated byS_or_a
which is either a stream or an alias. ISOget_code(Code)
Equivalent tocurrent_input(S), get_code(S, Code)
. ISOpeek_char(S_or_a, Char)
Similar toget_char(S_or_a, Char)
but doesn't consume the character. ISOpeek_char(Char)
Equivalent tocurrent_input(S), peek_char(S, Char)
. ISOpeek_code(S_or_a, Code)
Similar toget_code(S_or_a, Code)
but doesn't consume the code. ISOpeek_code(Code)
Equivalent tocurrent_input(S), peek_code(S, Code)
. ISOput_char(S_or_a, Char)
Outputs the characterChar
to the stream indicated byS_or_a
which is either a stream or an alias. ISOput_char(Char)
Equivalent tocurrent_output(S), put_char(S, Char)
. ISOput_code(S_or_a, Code)
Outputs the codeCode
to the stream indicated byS_or_a
which is either a stream or an alias. ISOput_code(Code)
Equivalent tocurrent_output(S), put_code(S, Code)
. ISOnl(S_or_a)
Outputs a newline to the stream indicated byS_or_a
which is either a stream or an alias. ISOnl
Equivalent tocurrent_output(S), nl(S)
. ISO
Byte input/output
get_byte(S_or_a, Byte)
Succeeds iffByte
unifies with the next byte from the stream indicated byS_or_a
which is a stream or an alias. ISOget_byte(Byte)
Equivalent tocurrent_input(S), get_byte(S, Byte)
. ISOpeek_byte(S_or_a, Byte)
Similar toget_byte(S_or_a, Byte)
but doesn't consume the byte. ISOpeek_byte(Byte)
Equivalent tocurrent_input(S), peek_byte(S, Byte)
. ISOput_byte(S_or_a, Byte)
Outputs the byteByte
to the stream indicated byS_or_a
which is either a stream or an alias. ISOput_byte(Byte)
Equivalent tocurrent_output(S), put_byte(S, Byte)
. ISO
Term input/output
read_term(S_or_a, Term, Options)
Succeeds iffTerm
unifies with the next term from the stream indicated byS_or_a
which is a stream or an alias. ISOOptions
is a list of read options listed below:variables(Vars)
the list of variables appeared inTerm
variable_names(VN_list)
the list ofA = V
whereA
is an atom which name is the string representation ofV
andV
is a variable appeared inTerm
singletons(VN_list)
similar tovariable_names(VN_list)
but those of variables that appeared once.
read_term(Term, Options)
Equivalent tocurrent_input(S), read_term(S, Term, Options)
. ISOread(S_or_a, Term)
Equivalent toread_term(S_or_a, Term, [])
. ISOread(Term)
Equivalent tocurrent_input(S), read(S, Term)
. ISOwrite_term(S_or_a, Term, Options)
OutputsTerm
to the stream indicated byS_or_a
which is either a stream or an alias. ISOOptions
is a list of write options listed below:quoted(Bool)
Bool
is eithertrue
orfalse
. Iftrue
, atoms and functors will be quoted as needed.ignore_ops(Bool)
Bool
is eithertrue
orfalse
. Iftrue
, operators will be written in functional notation.variable_names(VN_list)
VN_list
is a proper list which element is a form ofA = V
whereA
is an atom andV
is a variable. Each occurrence ofV
will be replaced by the leftmost and unquotedA
.numbervars(Bool)
Bool
is eithertrue
orfalse
. Iftrue
, terms'$VAR'(0)
,'$VAR'(1)
, ... will be written asA
,B
, ...
write_term(Term, Options)
Equivalent tocurrent_output(S), write_term(S, Term, Options)
. ISOwrite(S_or_a, Term)
Equivalent towrite_term(S_or_a, Term, [numbervars(true)])
. ISOwrite(Term)
Equivalent tocurrent_output(S), write(S, Term)
. ISOwriteq(S_or_a, Term)
Equivalent towrite_temr(S_or_a, Term, [quoted(true), numbervars(true)])
. ISOwriteq(Term)
Equivalent tocurrent_output(S), writeq(S, Term)
. ISOwrite_canonical(S_or_a, Term)
Equivalent towrite_term(S_or_a, Term, [quoted(true), ignore_ops(true)])
. ISOwrite_canonical(Term)
Equivalent tocurrent_output(S), write_canonical(S, Term)
. ISOop(Priority, Specifier, Operator)
Alters the operator table. ISOcurrent_op(Priority, Specifier, Operator)
Succeeds iff the operator indicated byPriority
,Specifier
,Operator
is in the operator table. ISOchar_conversion(In, Out)
Alters the character conversion mapping. ISOcurrent_char_conversion(In, Out)
Succeeds iff the character conversion fromIn
toOut
is in the conversion mapping. ISO
Logic and control
\+Goal
Succeeds iffcall(Goal)
fails. ISOonce(Goal)
CallsGoal
but never redoes. ISOrepeat
Repeats the following code until it succeeds. ISOcall(Closure, Arg1, ..., ArgN)
N = 1..7
. Succeeds iffcall(Goal)
whereGoal
isClosure
with additional argumentsArg1, ..., ArgN
. ISOfalse
Equivalent tofail
. ISObetween(Lower, Upper, X)
Succeeds iffLower <= X <= Upper
. prologue
Atomic term processing
atom_length(Atom, Length)
Succeeds iffLength
is the number of runes inAtom
. ISOatom_concat(Atom1, Atom2, Atom3)
Succeeds iffAtom3
is a concatenation ofAtom1
andAtom2
. ISOsub_atom(Atom, Before, Length, After, SubAtom)
Succeeds iffSubAtom
is a sub atom ofAtom
whereBefore
is the number of runes beforeSubAtom
,Length
is the length ofSubAtom
, andAfter
is the number of runes afterSubAtom
. ISOatom_chars(Atom, List)
Succeeds iffList
is the list of single-rune atoms thatAtom
consists of. ISOatom_codes(Atom, List)
Succeeds iffList
is the list of runes thatAtom
consists of. ISOchar_code(Char, Code)
Succeeds iffChar
is a single-rune atom which rune isCode
. ISOnumber_chars(Number, List)
Succeeds iffList
is the list of single-rune atoms that representsNumber
. ISOnumber_codes(Number, List)
Succeeds iffList
is the list of runes that representsNumber
. ISO
Implementation defined hooks
set_prolog_flag(Flag, Value)
Sets the Prolog flagFlag
toValue
. ISOFlag
is either:char_conversion
Value
is eitheron
oroff
(default).debug
Value
is eitheron
oroff
(default).unknown
Value
is eithererror
(default),fail
, orwarning
.double_quotes
Value
is eitherchars
(default),codes
, oratom
.
current_prolog_flag(Flag, Value)
Succeeds iffValue
is the current value for the Prolog flagFlag
. ISOFlag
is either:bounded
Value
is alwaystrue
.max_integer
Value
is always9223372036854775807
.min_integer
Value
is always-9223372036854775808
.integer_rounding_function
Value
is alwaystoward_zero
.char_conversion
Value
is eitheron
oroff
(default).debug
Value
is eitheron
oroff
(default).max_arity
Value
is alwaysunbounded
.unknown
Value
is eithererror
(default),fail
, orwarning
.double_quotes
Value
is eitherchars
(default),codes
, oratom
.
halt(X)
Exists the host program with the status code ofX
. ISOhalt
Equivalent tohalt(0)
. ISO
Definite clause grammars
expand_term(In, Out)
Succeeds iffOut
is an expansion of the termIn
.phrase(Phrase, List, Remainder)
Succeeds iff the different listList-Remainder
satisfies the grammar rulePhrase
.phrase(Phrase, List)
Equivalent tophrase(Phrase, List, [])
.
List processing
member(X, L)
Succeeds iffX
is a member of the listL
. prologueappend(Xs, Ys, Zs)
Succeeds iffZs
is the concatenation ofXs
andYs
. prologuelength(List, Length)
Succeeds iffLength
is the length ofList
. prologueselect(X, Xs, Ys)
Succeeds iffX
is an element ofXs
andYs
isXs
with one occurence ofX
removed. prologuemaplist(Goal, List1, ..., Listn)
n = 1..7
. Succeeds iffList1, ..., Listn
are the list of the same length andcall(Goal, List1_i, ..., Listn_i)
succeeds for all thei
-th elements ofList1, ..., Listn
. prologuenth0(N, List, Elem)
Succeeds iffElem
is theN
-th element ofList
counting from 0.nth1(N, List, Elem)
Succeeds iffElem
is theN
-th element ofList
counting from 1.
Program
consult(File)
Loads Prolog program files indicated byFile
.File
is either an atom or a list of atoms. An atomabc
indicates a Prolog program file./abc
or./abc.pl
.[File|Files]
Equivalent toconsult([File|Files])
.
Operating system interface
environ(Name, Value)
Succeeds iff the environment variableName
has the valueValue
.
Extensions
- predicates: Native predicates for ichiban/prolog.
License
Distributed under the MIT license. See LICENSE
for more information.
Contributing
See ARCHITECTURE.md
for architecture details.
- Fork it (https://github.com/ichiban/prolog/fork)
- Create your feature branch (git checkout -b feature/fooBar)
- Commit your changes (git commit -am 'Add some fooBar')
- Push to the branch (git push origin feature/fooBar)
- Create a new Pull Request
Acknowledgments
- A PORTABLE PROLOG COMPILER (Bowen et al. 83)
- ISO Prolog works by Prof. Ulrich Neumerkel
- SWI Prolog and its documentation
- GNU Prolog and its documentation