prolog

package module
v2.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 26, 2024 License: MIT Imports: 10 Imported by: 4

README ΒΆ

axone github banner

Β  Β  Β  Β 

Axone Prolog Virtual Machine

build codecov GoDoc Go Report Card conventional commits Contributor Covenant license

[!IMPORTANT] This repository is a hard fork of ichiban/prolog, customized to meet the specific requirements of the Axone protocol. It is maintained independently for our use case, and upstream updates may not be regularly integrated.

For the original, general-purpose Prolog implementation or to contribute to the broader community, please visit the ichiban/prolog repository.

What is this?

axone-protocol/prolog is a Prolog virtual machine written in Go, designed to be embedded in blockchain environments. It serves as the core of the Axone protocol for decentralized, logic-based smart contracts.

This project is a fork of the ichiban/prolog repository, striving to maintain ISO standard compliance where feasible while adapting to the unique constraints of blockchain execution.

Deviations from the ISO Standard

The following customizations have been made to adapt the original ichiban/prolog implementation to the blockchain environment:

  • Capped variable allocation to limit the number of variables.
  • Replaced maps with ordered maps to ensure deterministic execution.
  • Implemented secure integer arithmetic for functors.
  • Integrated cockroachdb/apd for floating-point arithmetic.
  • Removed support for trigonometric functions (sin, cos, tan, asin, acos, atan).
  • Introduced VM hooks for enhanced Prolog execution control.
  • Added support for the Dict term.
  • halt/0 and halt/1 are forbidden and will throw an error.

License

Distributed under the MIT license. See LICENSE for more information.

Bug reports & feature requests

If you notice anything not behaving how you expected, if you would like to make a suggestion or would like to request a new feature, please open a new issue. We appreciate any help you're willing to give!

Don't hesitate to ask if you are having trouble setting up your project repository, creating your first branch or configuring your development environment. Mentors and maintainers are here to help!

You want to get involved? 😍

So you want to contribute? Great! ❀️ We appreciate any help you're willing to give. Don't hesitate to open issues and/or submit pull requests.

We believe that collaboration is key to the success of the Axone project. Join our Community discussions on the Community space to:

  • Engage in conversations with peers and experts.
  • Share your insights and experiences with Axone.
  • Learn from others and expand your knowledge of the protocol.

The Community space serves as a hub for discussions, questions, and knowledge-sharing related to Axone. We encourage you to actively participate and contribute to the growth of our community.

Please check out Axone health files:

Acknowledgements

We would like to thank the following projects for their inspiration and for providing the foundation for this project:

  • ichiban for the original Prolog implementation.

Documentation ΒΆ

Index ΒΆ

Examples ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

View Source
var ErrClosed = errors.New("closed")

ErrClosed indicates the Solutions are already closed and unable to perform the operation.

View Source
var ErrNoSolutions = errors.New("no solutions")

ErrNoSolutions indicates there's no solutions for the query.

Functions ΒΆ

This section is empty.

Types ΒΆ

type Interpreter ΒΆ

type Interpreter struct {
	engine.VM
}

Interpreter is a Prolog interpreter.

func New ΒΆ

func New(in io.Reader, out io.Writer) *Interpreter

New creates a new Prolog interpreter with predefined predicates/operators.

Example (AcyclicTerm) ΒΆ
p := New(nil, nil)

sols, _ := p.Query(`acyclic_term(a(1, _)).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`X = f(X), acyclic_term(X).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()
Output:

true
false
Example (Arg) ΒΆ
p := New(nil, nil)

sols, _ := p.Query(`arg(1, foo(a, b), a).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`arg(1, foo(a, b), X).`)
for sols.Next() {
	var s struct {
		X string
	}
	_ = sols.Scan(&s)
	fmt.Printf("X = %s\n", s.X)
}
_ = sols.Close()

sols, _ = p.Query(`arg(1, foo(X, b), a).`)
for sols.Next() {
	var s struct {
		X string
	}
	_ = sols.Scan(&s)
	fmt.Printf("X = %s\n", s.X)
}
_ = sols.Close()

sols, _ = p.Query(`arg(1, foo(X, b), Y), X = a.`)
for sols.Next() {
	var s struct {
		X, Y string
	}
	_ = sols.Scan(&s)
	fmt.Printf("X = %s, Y = %s\n", s.X, s.Y)
}
_ = sols.Close()

sols, _ = p.Query(`arg(1, foo(a, b), b).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`arg(0, foo(a, b), foo).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`arg(3, foo(a, b), N).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`arg(X, foo(a, b), a).`)
sols.Next()
fmt.Printf("%v\n", sols.Err())
_ = sols.Close()

sols, _ = p.Query(`arg(1, X, a).`)
sols.Next()
fmt.Printf("%v\n", sols.Err())
_ = sols.Close()

sols, _ = p.Query(`arg(0, atom, A).`)
sols.Next()
fmt.Printf("%v\n", sols.Err())
_ = sols.Close()

sols, _ = p.Query(`arg(0, 3, A).`)
sols.Next()
fmt.Printf("%v\n", sols.Err())
_ = sols.Close()
Output:

true
X = a
X = a
X = a, Y = a
false
false
false
error(instantiation_error,arg/3)
error(instantiation_error,arg/3)
error(type_error(compound,atom),arg/3)
error(type_error(compound,3),arg/3)
Example (Callable) ΒΆ
p := New(nil, nil)

sols, _ := p.Query(`callable(a).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`callable(3).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`callable(X).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`callable((1,2)).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()
Output:

true
false
false
true
Example (Ground) ΒΆ
p := New(nil, nil)

sols, _ := p.Query(`ground(3).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`ground(a(1, _)).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()
Output:

true
false
Example (Phrase) ΒΆ
p := New(nil, nil)
_ = p.Exec(`
determiner --> [the].
determiner --> [a].

noun --> [boy].
noun --> [girl].

verb --> [likes].
verb --> [scares].

noun_phrase --> determiner, noun.
noun_phrase --> noun.

verb_phrase --> verb.
verb_phrase --> verb, noun_phrase.

sentence --> noun_phrase, verb_phrase.
`)

sols, _ := p.Query(`phrase([the], [the]).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`phrase(sentence, [the, girl, likes, the, boy]).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`phrase(sentence, [the, girl, likes, the, boy, today]).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`phrase(sentence, [the, girl, likes]).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`phrase(sentence, Sentence).`)
for sols.Next() {
	var s struct {
		Sentence []string
	}
	_ = sols.Scan(&s)
	fmt.Printf("Sentence = %s\n", s.Sentence)
	break // Many other sentences follow.
}
_ = sols.Close()

sols, _ = p.Query(`phrase(noun_phrase, [the, girl, scares, the, boy], Rest).`)
for sols.Next() {
	var s struct {
		Rest []string
	}
	_ = sols.Scan(&s)
	fmt.Printf("Rest = %s\n", s.Rest)
}
_ = sols.Close()
Output:

true
true
false
true
Sentence = [the boy likes]
Rest = [scares the boy]
Example (Sort) ΒΆ
p := New(nil, nil)

sols, _ := p.Query(`sort([1, 1], Sorted).`)
for sols.Next() {
	var s struct {
		Sorted []int
	}
	_ = sols.Scan(&s)
	fmt.Printf("Sorted = %d\n", s.Sorted)
}
_ = sols.Close()

sols, _ = p.Query(`sort([X, 1], [1, 1]).`)
for sols.Next() {
	var s struct {
		X int
	}
	_ = sols.Scan(&s)
	fmt.Printf("X = %d\n", s.X)
}
_ = sols.Close()

sols, _ = p.Query(`sort([1, 1], [1, 1]).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`sort([V], V).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`sort([f(U),U,U,f(V),f(U),V],L).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()
Output:

Sorted = [1]
X = 1
false
true
true
Example (Subsumes_term) ΒΆ
p := New(nil, nil)

sols, _ := p.Query(`subsumes_term(a, a).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`subsumes_term(f(X,Y), f(Z,Z)).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`subsumes_term(f(Z,Z), f(X,Y)).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`subsumes_term(g(X), g(f(X))).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`subsumes_term(X, f(X)).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()

sols, _ = p.Query(`subsumes_term(X, Y), subsumes_term(Y, f(X)).`)
fmt.Printf("%t\n", sols.Next())
_ = sols.Close()
Output:

true
true
false
false
false
true

func NewEmpty ΒΆ

func NewEmpty() *Interpreter

NewEmpty creates a new Prolog interpreter without any predicates/operators defined.

func (*Interpreter) Exec ΒΆ

func (i *Interpreter) Exec(query string, args ...interface{}) error

Exec executes a prolog program.

Example (Placeholders) ΒΆ
p := New(nil, os.Stdout)

_ = p.Exec(`my_string(?).`, "foo")
sols, _ := p.Query(`my_string(A), maplist(atom, A), write(A), nl.`)
sols.Next()
_ = sols.Close()

_ = p.Exec(`my_int(?, ?, ?, ?, ?).`, int8(1), int16(1), int32(1), int64(1), 1)
sols, _ = p.Query(`my_int(I, I, I, I, I), integer(I), write(I), nl.`)
sols.Next()
_ = sols.Close()

_ = p.Exec(`my_atom_list(?).`, []string{"foo", "bar", "baz"})
sols, _ = p.Query(`my_atom_list(As), maplist(maplist(atom), As), write(As), nl.`)
sols.Next()
_ = sols.Close()

_ = p.Exec(`my_int_list(?).`, []int{1, 2, 3})
sols, _ = p.Query(`my_int_list(Is), maplist(integer, Is), write(Is), nl.`)
sols.Next()
_ = sols.Close()
Output:

[f,o,o]
1
[[f,o,o],[b,a,r],[b,a,z]]
[1,2,3]

func (*Interpreter) ExecContext ΒΆ

func (i *Interpreter) ExecContext(ctx context.Context, query string, args ...interface{}) error

ExecContext executes a prolog program with context.

func (*Interpreter) Query ΒΆ

func (i *Interpreter) Query(query string, args ...interface{}) (*Solutions, error)

Query executes a prolog query and returns *Solutions.

Example (Placeholders) ΒΆ
p := New(nil, os.Stdout)
sols, _ := p.Query(`A = ?, maplist(atom, A), write(A), nl.`, "foo")
sols.Next()
_ = sols.Close()
sols, _ = p.Query(`(I, I, I, I, I) = (?, ?, ?, ?, ?), integer(I), write(I), nl.`, int8(1), int16(1), int32(1), int64(1), 1)
sols.Next()
_ = sols.Close()
sols, _ = p.Query(`L = ?, maplist(maplist(atom), L), write(L), nl.`, []string{"foo", "bar", "baz"})
sols.Next()
_ = sols.Close()
sols, _ = p.Query(`L = ?, maplist(integer, L), write(L), nl.`, []int{1, 2, 3})
sols.Next()
_ = sols.Close()
Output:

[f,o,o]
1
[[f,o,o],[b,a,r],[b,a,z]]
[1,2,3]

func (*Interpreter) QueryContext ΒΆ

func (i *Interpreter) QueryContext(ctx context.Context, query string, args ...interface{}) (*Solutions, error)

QueryContext executes a prolog query and returns *Solutions with context.

func (*Interpreter) QuerySolution ΒΆ

func (i *Interpreter) QuerySolution(query string, args ...interface{}) *Solution

QuerySolution executes a Prolog query for the first solution.

func (*Interpreter) QuerySolutionContext ΒΆ

func (i *Interpreter) QuerySolutionContext(ctx context.Context, query string, args ...interface{}) *Solution

QuerySolutionContext executes a Prolog query with context.

type Scanner ΒΆ

type Scanner interface {
	Scan(vm *engine.VM, term engine.Term, env *engine.Env) error
}

Scanner is an interface for custom conversion from term to Go value.

type Solution ΒΆ

type Solution struct {
	// contains filtered or unexported fields
}

Solution is the single result of a query.

func (*Solution) Err ΒΆ

func (s *Solution) Err() error

Err returns an error that occurred while querying for the Solution, if any.

func (*Solution) Scan ΒΆ

func (s *Solution) Scan(dest interface{}) error

Scan copies the variable values of the solution into the specified struct/map.

type Solutions ΒΆ

type Solutions struct {
	// contains filtered or unexported fields
}

Solutions is the result of a query. Everytime the Next method is called, it searches for the next solution. By calling the Scan method, you can retrieve the content of the solution.

func (*Solutions) Close ΒΆ

func (s *Solutions) Close() error

Close closes the Solutions and terminates the search for other solutions.

func (*Solutions) Err ΒΆ

func (s *Solutions) Err() error

Err returns the error if exists.

func (*Solutions) Next ΒΆ

func (s *Solutions) Next() bool

Next prepares the next solution for reading with the Scan method. It returns true if it finds another solution, or false if there's no further solutions or if there's an error.

func (*Solutions) Scan ΒΆ

func (s *Solutions) Scan(dest interface{}) error

Scan copies the variable values of the current solution into the specified struct/map.

Example ΒΆ
p := New(nil, nil)
sols, _ := p.Query(`A = foo, I = 42, F = 3.14.`)
for sols.Next() {
	var s struct {
		A string
		I int
		F string
	}
	_ = sols.Scan(&s)
	fmt.Printf("A = %s\n", s.A)
	fmt.Printf("I = %d\n", s.I)
	fmt.Printf("F = %s\n", s.F)
}
Output:

A = foo
I = 42
F = 3.14
Example (List) ΒΆ
p := New(nil, nil)
sols, _ := p.Query(`Atoms = [foo, bar], Integers = [1, 2], Floats = [1.1, 2.1], Mixed = [foo, 1, 1.1].`)
for sols.Next() {
	var s struct {
		Atoms    []string
		Integers []int64
		Floats   []string
		Mixed    []interface{}
	}
	_ = sols.Scan(&s)

	fmt.Printf("Atoms = %s\n", s.Atoms)
	fmt.Printf("Integers = %d\n", s.Integers)
	fmt.Printf("Floats = %s\n", s.Floats)
	fmt.Printf("Mixed = %v\n", s.Mixed)
}
Output:

Atoms = [foo bar]
Integers = [1 2]
Floats = [1.1 2.1]
Mixed = [foo 1 1.1]
Example (Tag) ΒΆ
p := New(nil, nil)
sols, _ := p.Query(`A = foo, I = 42, F = 3.14.`)
for sols.Next() {
	var s struct {
		Atom    string `prolog:"A"`
		Integer int    `prolog:"I"`
		Float   string `prolog:"F"`
	}
	_ = sols.Scan(&s)
	fmt.Printf("Atom = %s\n", s.Atom)
	fmt.Printf("Integer = %d\n", s.Integer)
	fmt.Printf("Float = %s\n", s.Float)
}
Output:

Atom = foo
Integer = 42
Float = 3.14

type TermString ΒΆ

type TermString string

TermString is a string representation of term.

func (*TermString) Scan ΒΆ

func (t *TermString) Scan(vm *engine.VM, term engine.Term, env *engine.Env) error

Scan implements Scanner interface.

Directories ΒΆ

Path Synopsis
cmd
1pl
examples
dcg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL