prolog
prolog copied to clipboard
The only reasonable scripting engine for Go.
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 | 🎓 Logic | 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 byPIare 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 byPIare built-in.
Predicates
Control constructs
trueAlways succeeds. ISOfailAlways fails. ISOcall(Goal)CallsGoal. ISO!Cut. ISOP, QConjunction. ISOP; QDisjunction. ISOIf -> ThenIf-then. ISOIf -> Then; ElseIf-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 = YUnifiesXwithY. ISOunify_with_occurs_check(X, Y)UnifiesXwithYwith occurs check. ISOX \= YSucceeds iffXandYare not unifiable. ISOsubsumes_term(General, Specific)Succeeds iff there's a substitutionθsuch thatGeneralθ = SpecificθandSpecificθ = Specific. ISO
Type testing
var(X)Succeeds iffXis a variable. ISOatom(X)Succeeds iffXis an atom. ISOinteger(X)Succeeds iffXis an integer. ISOfloat(X)Succeeds iffXis a float. ISOatomic(X)Succeeds iffXis neither a variable nor a compound. ISOcompound(X)Succeeds iffXis a compound. ISOnonvar(X)Succeeds iffXis not a variable. ISOnumber(X)Succeeds iffXis either an integer or a float. ISOcallable(X)Succeeds iffXis either an atom or a compound. ISOground(X)Succeeds iffXis a ground term. ISOacyclic_term(X)Succeeds iffXis acyclic. ISO
Term comparison
X @=< YEitherX == YorX @< Y. ISOX == YEquivalent tocompare(=, X, Y). ISOX \== YEquivalent to\+compare(=, X, Y). ISOX @< YEquivalent tocompare(<, X, Y). ISOX @> YEquivalent tocompare(>, X, Y). ISOX @>= YEitherX == YorX @> Y. ISOcompare(Order, X, Y)ComparesXandYand unifiesOrderwith either<,=, or>. ISOsort(List, Sorted)Succeeds iffSortedunifies with a sorted list ofList. ISOkeysort(Pairs, Sorted)Succeeds iffPairsis a list ofKey-Valuepairs andSortedunifies with a permutation ofPairssorted byKey. ISO
Term creation and decomposition
functor(Term, Name, Arity)Succeeds iffTermia either a compound term ofNameandArityor an atom ofNameandArity = 0. ISOarg(N, Term, Arg)Succeeds iffArgis theN-th argument ofTerm. ISOTerm =.. ListSucceeds iffListis a list of the functor and arguments ofTerm. ISOcopy_term(Term1, Term2)Creates a copy ofTerm1and unifies it withTerm2. ISOterm_variables(Term, Vars)Succeeds iffVarsis a list of variables appear inTerm. ISO
Arithmetic evaluation
Result is ExpressionEvaluatesExpressionand unifies it withResult. ISOExpressionis either:-
integer,
-
float, or
-
evaluable functors
X + YX - YX * YX // YX / YX rem YX mod Y-Xabs(X)sign(X)float_integer_part(X)float_fractional_part(X)float(X)floor(X)truncate(X)round(X)ceiling(X)+(X)X div YX ** Ysin(X)cos(X)atan(X)exp(X)log(X)sqrt(X)max(X, Y)min(X, Y)X ^ Yasin(X)acos(X)atan2(X, Y)tan(X)piX >> YX << YX /\ YX \/ Y\Xxor(X, Y)
-
succ(X, S)Succeeds iffSis the successor of the non-negative integerX. prologue
Arithmetic comparison
E1 =:= E2Succeeds iffE1andE2are evaluated toEV1andEV2respectively andEV1equals toEV2. ISOE1 =\= E2Succeeds iffE1andE2are evaluated toEV1andEV2respectively andEV1does not equal toEV2. ISOE1 < E2Succeeds iffE1andE2are evaluated toEV1andEV2respectively andEV1is greater thanEV2. ISOE1 =< E2Succeeds iffE1andE2are evaluated toEV1andEV2respectively andEV1is greater than or equal toEV2. ISOE1 > E2Succeeds iffE1andE2are evaluated toEV1andEV2respectively andEV1is less thanEV2. ISOE1 >= E2Succeeds iffE1andE2are evaluated toEV1andEV2respectively andEV1is less than or equal toEV2. ISO
Clause retrieval and information
clause(Head, Body)Succeeds iffHead :- Bodyunifies with a clause in the DB. ISOcurrent_predicate(PI)Succeeds iff the predicate indicated byPIis in the DB. ISO
Clause creation and destruction
asserta(Clause)PrependsClauseto the DB. ISOassertz(Clause)AppendsClauseto the DB. ISOretract(Clause)Removes a clause that unifies withClausefrom the DB. ISOabolish(PI)Removes the predicate indicated byPIfrom the DB. ISOretractall(Head)Removes all the clauses which head unifies withHeadfrom the DB. ISO
All solutions
findall(Template, Goal, Instances)Succeeds iffInstancesunifies with a list ofTemplatefor each solution ofGoal. ISObagof(Template, Goal, Instances)Succeeds iffInstancesunifies with a bag (multiset) ofTemplatefor each solution ofGoal. ISOsetof(Template, Goal, Instances)Succeeds iffInstancesunifies with a set ofTemplatefor each solution ofGoal. ISO
Stream selection and control
current_input(Stream)Succeeds iffStreamunifies with the current input stream. ISOcurrent_output(Stream)Succeeds iffStreamunifies with the current output stream. ISOset_input(S_or_a)Sets the current input stream to the stream indicated byS_or_awhich is either the stream itself or its alias. ISOset_output(S_or_a)Sets the current output stream to the stream indicated byS_or_awhich is either the stream itself or its alias. ISOopen(File, Mode, Stream, Options)Opens the fileFileinModewithOptionsand unifies the stream withStream. ISOModeis either:read,write, orappend.Optionsis a list of stream options listed below:type(T)Specifies the type of the stream.Tis eithertext(default) orbinary.reposition(Bool)Specifies if the stream can be repositions.Boolis eithertrueorfalse.alias(A)Specifies the alias for the stream.Ais an atom.eof_action(Action)Specifies the action that will be taken when the input stream reached to the end.Actionis either:errorwhich throws an exception,eof_codewhich returns a value indicating the end of stream (default), orresetwhich resets the stream.
open(File, Mode, Stream)Equivalent toopen(File, Mode, Stream, []). ISOclose(S_or_a, Options)Closes the stream indicated byS_or_awhich is the stream itself or its alias. ISOOptionsis a list of:force(Bool)Specifies if an exception will be raised when it failed to close the stream.Boolis 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_awhich is either the stream itself or its alias. ISOflush_outputEquivalent tocurrent_output(S), flush_output(S). ISOstream_property(Stream, Property)Succeeds iff the streamStreamhas the propertyProperty. ISOPropertyis either:file_name(F)mode(M)inputoutputalias(A)position(P)end_of_stream(E)eof_action(A)reposition(Bool)type(T)
at_end_of_streamEquivalent tocurrent_input(S), at_end_of_stream(S). ISOat_end_of_stream(S_or_a)Succeeds iff the stream indicated byS_or_awhich 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_awhich is either a stream or an alias to the positionPosition. ISO
Character input/output
get_char(S_or_a, Char)Succeeds iffCharunifies with the next character from the stream indicated byS_or_awhich 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 iffCharunifies with the next code from the stream indicated byS_or_awhich 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 characterCharto the stream indicated byS_or_awhich 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 codeCodeto the stream indicated byS_or_awhich 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_awhich is either a stream or an alias. ISOnlEquivalent tocurrent_output(S), nl(S). ISO
Byte input/output
get_byte(S_or_a, Byte)Succeeds iffByteunifies with the next byte from the stream indicated byS_or_awhich 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 byteByteto the stream indicated byS_or_awhich 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 iffTermunifies with the next term from the stream indicated byS_or_awhich is a stream or an alias. ISOOptionsis a list of read options listed below:variables(Vars)the list of variables appeared inTermvariable_names(VN_list)the list ofA = VwhereAis an atom which name is the string representation ofVandVis a variable appeared inTermsingletons(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)OutputsTermto the stream indicated byS_or_awhich is either a stream or an alias. ISOOptionsis a list of write options listed below:quoted(Bool)Boolis eithertrueorfalse. Iftrue, atoms and functors will be quoted as needed.ignore_ops(Bool)Boolis eithertrueorfalse. Iftrue, operators will be written in functional notation.variable_names(VN_list)VN_listis a proper list which element is a form ofA = VwhereAis an atom andVis a variable. Each occurrence ofVwill be replaced by the leftmost and unquotedA.numbervars(Bool)Boolis eithertrueorfalse. 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,Operatoris in the operator table. ISOchar_conversion(In, Out)Alters the character conversion mapping. ISOcurrent_char_conversion(In, Out)Succeeds iff the character conversion fromIntoOutis in the conversion mapping. ISO
Logic and control
\+GoalSucceeds iffcall(Goal)fails. ISOonce(Goal)CallsGoalbut never redoes. ISOrepeatRepeats the following code until it succeeds. ISOcall(Closure, Arg1, ..., ArgN)N = 1..7. Succeeds iffcall(Goal)whereGoalisClosurewith additional argumentsArg1, ..., ArgN. ISOfalseEquivalent tofail. ISObetween(Lower, Upper, X)Succeeds iffLower <= X <= Upper. prologue
Atomic term processing
atom_length(Atom, Length)Succeeds iffLengthis the number of runes inAtom. ISOatom_concat(Atom1, Atom2, Atom3)Succeeds iffAtom3is a concatenation ofAtom1andAtom2. ISOsub_atom(Atom, Before, Length, After, SubAtom)Succeeds iffSubAtomis a sub atom ofAtomwhereBeforeis the number of runes beforeSubAtom,Lengthis the length ofSubAtom, andAfteris the number of runes afterSubAtom. ISOatom_chars(Atom, List)Succeeds iffListis the list of single-rune atoms thatAtomconsists of. ISOatom_codes(Atom, List)Succeeds iffListis the list of runes thatAtomconsists of. ISOchar_code(Char, Code)Succeeds iffCharis a single-rune atom which rune isCode. ISOnumber_chars(Number, List)Succeeds iffListis the list of single-rune atoms that representsNumber. ISOnumber_codes(Number, List)Succeeds iffListis the list of runes that representsNumber. ISO
Implementation defined hooks
set_prolog_flag(Flag, Value)Sets the Prolog flagFlagtoValue. ISOFlagis either:char_conversionValueis eitheronoroff(default).debugValueis eitheronoroff(default).unknownValueis eithererror(default),fail, orwarning.double_quotesValueis eitherchars(default),codes, oratom.
current_prolog_flag(Flag, Value)Succeeds iffValueis the current value for the Prolog flagFlag. ISOFlagis either:boundedValueis alwaystrue.max_integerValueis always9223372036854775807.min_integerValueis always-9223372036854775808.integer_rounding_functionValueis alwaystoward_zero.char_conversionValueis eitheronoroff(default).debugValueis eitheronoroff(default).max_arityValueis alwaysunbounded.unknownValueis eithererror(default),fail, orwarning.double_quotesValueis eitherchars(default),codes, oratom.
halt(X)Exists the host program with the status code ofX. ISOhaltEquivalent tohalt(0). ISO
Definite clause grammars
expand_term(In, Out)Succeeds iffOutis an expansion of the termIn.phrase(Phrase, List, Remainder)Succeeds iff the different listList-Remaindersatisfies the grammar rulePhrase.phrase(Phrase, List)Equivalent tophrase(Phrase, List, []).
List processing
member(X, L)Succeeds iffXis a member of the listL. prologueappend(Xs, Ys, Zs)Succeeds iffZsis the concatenation ofXsandYs. prologuelength(List, Length)Succeeds iffLengthis the length ofList. prologueselect(X, Xs, Ys)Succeeds iffXis an element ofXsandYsisXswith one occurence ofXremoved. prologuemaplist(Goal, List1, ..., Listn)n = 1..7. Succeeds iffList1, ..., Listnare 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 iffElemis theN-th element ofListcounting from 0.nth1(N, List, Elem)Succeeds iffElemis theN-th element ofListcounting from 1.
Program
consult(File)Loads Prolog program files indicated byFile.Fileis either an atom or a list of atoms. An atomabcindicates a Prolog program file./abcor./abc.pl.[File|Files]Equivalent toconsult([File|Files]).
Operating system interface
environ(Name, Value)Succeeds iff the environment variableNamehas 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
