prolog icon indicating copy to clipboard operation
prolog copied to clipboard

Working with lists

Open riccardopinosio opened this issue 2 years ago • 7 comments

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!

riccardopinosio avatar Mar 14 '22 11:03 riccardopinosio

@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 avatar Mar 15 '22 01:03 ichiban

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 avatar Mar 15 '22 01:03 ichiban

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)
}

ichiban avatar Mar 15 '22 09:03 ichiban

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

riccardopinosio avatar Mar 15 '22 16:03 riccardopinosio

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

triska avatar Mar 15 '22 19:03 triska

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

ichiban avatar Mar 19 '22 04:03 ichiban

The example above https://github.com/ichiban/prolog/issues/160#issuecomment-1067757579 is in the package documentation now

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

ichiban avatar Apr 02 '22 08:04 ichiban

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 avatar Dec 16 '22 02:12 ichiban

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

ichiban avatar Dec 16 '22 02:12 ichiban