prolog
prolog copied to clipboard
Working with lists
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 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
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
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 cool! Would the example with returning lists also be a good candidate for the /examples folder?
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
@riccardopinosio I think this should be also a testable example so that we can know when we break it accidentally.
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
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)
I'm going to close this issue for now. Feel free to reopen it if anything unclear!