Skip to content

Commit 1cc65bb

Browse files
committed
Make len fully relational
1 parent 5082daa commit 1cc65bb

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

solutions/lists.mod

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,29 @@ nth [_|Xs] N X :- N > 0
3636
& nth Xs {calc (N - 1)} X.
3737

3838
% 1.04
39-
pred len o:list A, o: Int.
40-
len [] 0.
41-
len [_|T] N :- N is {len T} + 1.
39+
pred len o:list A, o:int.
40+
% `len Ls N` is true when `N` is the length of `Ls`.
41+
pred len.aux o:list A, o:int.
42+
% When `N` is bound, we count down from `N` to `0`, removing one element of
43+
% `Ls` with each unit of `N` removed. If we arrive at `[]` and `0` at the
44+
% same time, we are done, and cannot possibly have more conclusions (thus the cut).
45+
len Ls N :- not (var N),
46+
( len.aux [] 0
47+
& pi T M M'\
48+
len.aux [_|T] M :- M' is M - 1,
49+
len.aux T M'
50+
) => len.aux Ls N, !.
51+
% When `N` is free, then we count up, starting from `0` to `N`, constructing
52+
% a list by adding a free variable to our list each time a unit is added to
53+
% `N`. When the list we're constructing can be unified with the input `Ls`
54+
% then we're at our `N`. If `Ls` is left partial in the tail, then we can
55+
% keep generating longer lists for `Ls` on backtracking.
56+
len Ls N :- var N,
57+
( len.aux Ls N
58+
& pi L M M'\
59+
len.aux L M :- M' is M + 1,
60+
len.aux [_|L] M'
61+
) => len.aux [] 0.
4262

4363
% 1.05
4464
pred rev o:list A, o:list A.

0 commit comments

Comments
 (0)