In SWI Prolog, list(Xs) :- length(Xs, _).
is "pure" in that I can pass it a variable with any sort of instantiatedness and it will nondeterministically unify it with all most general unifiers of a particular length.
Is it possible to write a pure list/1
in Mercury? The manual seemed to hint this could be done, but I'm having trouble actually implementing it.
What I have so far is:
:- module mylist.
:- interface.
:- import_module list.
:- inst frees for list/1
---> []
; [free | frees].
:- mode free_to_frees == free >> frees.
:- pred mylist(list(_)).
:- mode mylist(in) is det.
:- mode mylist(free_to_frees) is multi.
:- implementation.
:- pragma promise_pure(mylist/1).
mylist(_::in).
mylist([]::free_to_frees).
mylist([_|Xs]::free_to_frees) :- mylist(Xs).
However, when I try this:
:- module main.
:- interface.
:- implementation.
:- import_module list, mylist.
:- pred getlist(list(int)).
:- mode getlist(free >> ground) is multi.
getlist(Xs) :- Xs = [1, 2, 3].
getlist(Xs) :- mylist(Xs), Xs = [5].
I get the following error:
main.m:011: In clause for `getlist(out)':
main.m:011: mode error in conjunction. The next 2 error messages indicate
main.m:011: possible causes of this error.
main.m:011:
main.m:011: In clause for `getlist(out)':
main.m:011: mode error in unification of `Xs' and `list.[V_10 | V_16]'.
main.m:011: Variable `Xs' has instantiatedness
main.m:011: bound(
main.m:011: []
main.m:011: ;
main.m:011: '[|]'(
main.m:011: free,
main.m:011: named inst mylist.listskel,
main.m:011: which expands to
main.m:011: bound(
main.m:011: []
main.m:011: ;
main.m:011: '[|]'(
main.m:011: free,
main.m:011: named inst mylist.listskel
main.m:011: )
main.m:011: )
main.m:011: )
main.m:011: ),
main.m:011: term `list.[V_10 | V_16]' has instantiatedness
main.m:011: `named inst list.'[|]'(unique(5), free)'.
main.m:011:
main.m:011: In clause for `getlist(out)':
main.m:011: in argument 1 of clause head:
main.m:011: mode error in unification of `HeadVar__1' and `Xs'.
main.m:011: Variable `HeadVar__1' has instantiatedness `free',
main.m:011: variable `Xs' has instantiatedness
main.m:011: bound(
main.m:011: []
main.m:011: ;
main.m:011: '[|]'(
main.m:011: free,
main.m:011: named inst mylist.listskel,
main.m:011: which expands to
main.m:011: bound(
main.m:011: []
main.m:011: ;
main.m:011: '[|]'(
main.m:011: free,
main.m:011: named inst mylist.listskel
main.m:011: )
main.m:011: )
main.m:011: )
main.m:011: ).
I'm guessing my use of free
may be incorrect, or else I need to add an additional mode or generalize my listskel
inst to cover the case of mylist(Xs), Xs = [5]
.
Basically, how should I write mylist/1
, so that it can be used in as many modes as possible?
Thank you!