Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working with lists #160

Closed
riccardopinosio opened this issue Mar 14, 2022 · 9 comments
Closed

Working with lists #160

riccardopinosio opened this issue Mar 14, 2022 · 9 comments

Comments

@riccardopinosio
Copy link

riccardopinosio commented Mar 14, 2022

Hi, I'm trying to experiment more with lists in the library but I'm struggling a bit, maybe you can help.
Given the program:

is_comparison(a).
comparison_list(a, [1.0, 2.0]).
score(X,Y) :- is_comparison(X), comparison_list(X,Z), nth(0, Z, W), Y is W.

I would expect the query score(Comparison, Score) to return a pair (a, 1.0) in the below code:

	// Prolog program invocation takes a form of query.
	sols, err := p.Query(`score(Comparison, Score).`)
	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 {
			Comparison string
			Score      float64
		}
		if err := sols.Scan(&s); err != nil {
			panic(err)
		}
		fmt.Printf("%#v\n", s)
	}

but it doesn't seem to return anything. Am I making a mistake here? Is the usage of the nth predicate correct?

Second thing on lists. I would like to calculate a sum of elements in a list of numbers. I see it's not a builtin currently, so I assume I could just define it as a custom predicate using recursion (like her https://stackoverflow.com/questions/9875760/sum-of-elements-in-list-in-prolog).

Third thing on lists: is it possible to return a prolog list into go? How would I specify the types in the struct?

Thanks!

@ichiban
Copy link
Owner

ichiban commented Mar 15, 2022

@riccardopinosio Hi, I think the first problem boils down to nth(0, [1.0, 2.0], W). There're 2 problems:

nth/3 is not released yet

I've added nth/3 to the main branch but not released yet! The current release is v0.8.0 and it'll be included in v0.9.0 with other ISO standard / de facto standard predicates.

nth/3 counts from 1

I implemented nth/3 to imitate one in GNU Prolog so it counts from 1.

$ gprolog 
GNU Prolog 1.5.0 (64 bits)
Compiled Oct 29 2021, 07:27:11 with clang
Copyright (C) 1999-2021 Daniel Diaz

| ?- nth(0, [1.0, 2.0], W).

no
| ?- nth(1, [1.0, 2.0], W).

W = 1.0

yes

@ichiban
Copy link
Owner

ichiban commented Mar 15, 2022

On the 2nd thing, as far as I know, there's no standard predicate to do the sum of elements.
So I think it's better off not supporting it out of the box.

I think this answer matches your requirement: https://stackoverflow.com/revisions/12413025/2

@ichiban
Copy link
Owner

ichiban commented Mar 15, 2022

Regarding the 3rd point, yes, you can return lists into Go! Here's how you do it: https://go.dev/play/p/ZLT0n98z8JG

package main

import (
	"fmt"

	"github.com/ichiban/prolog"
)

func main() {
	p := prolog.New(nil, nil)

	sol := p.QuerySolution(`Atoms = [foo, bar], Integers = [1, 2], Floats = [1.0, 2.0], Mixed = [foo, 1, 1.0].`)

	var s struct {
		Atoms    []string
		Integers []int64
		Floats   []float64
		Mixed    []interface{}
	}
	if err := sol.Scan(&s); err != nil {
		panic(err)
	}

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

@riccardopinosio
Copy link
Author

@ichiban cool! Would the example with returning lists also be a good candidate for the /examples folder?

@triska
Copy link

triska commented Mar 15, 2022

Regarding predicate names, I highly recommend the SICStus API of library(lists), which supports nth0/3 and nth1/3 to make clear whether it is 0- or 1-based:

https://sicstus.sics.se/sicstus/docs/4.6.0/html/sicstus/lib_002dlists.html

@ichiban
Copy link
Owner

ichiban commented Mar 19, 2022

@riccardopinosio I think this should be also a testable example so that we can know when we break it accidentally.

@ichiban
Copy link
Owner

ichiban commented Apr 2, 2022

The example above #160 (comment) is in the package documentation now

https://pkg.go.dev/github.com/ichiban/prolog#example-Solutions.Scan-List

@ichiban
Copy link
Owner

ichiban commented Dec 16, 2022

Now that we've added nth0/3, the original program can work with a slight modification:

package main

import (
	"fmt"
	"github.com/ichiban/prolog"
)

func main() {
	p := prolog.New(nil, nil)

	if err := p.Exec(`
		is_comparison(a).
		comparison_list(a, [1.0, 2.0]).
		score(X,Y) :- is_comparison(X), comparison_list(X,Z), nth0(0, Z, Y).
	`); err != nil {
		panic(err)
	}

	// Prolog program invocation takes a form of query.
	sols, err := p.Query(`score(Comparison, Score).`)
	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 {
			Comparison string
			Score      float64
		}
		if err := sols.Scan(&s); err != nil {
			panic(err)
		}
		fmt.Printf("(%s, %.1f)\n", s.Comparison, s.Score)
	}
}
(a, 1.0)

@ichiban
Copy link
Owner

ichiban commented Dec 16, 2022

I'm going to close this issue for now. Feel free to reopen it if anything unclear!

@ichiban ichiban closed this as completed Dec 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants