Prolog 中是否有等同于 Haskell 的 enumFromTo?
Is there an equivalent of Haskell's enumFromTo in Prolog?
我刚开始使用 Prolog,我希望执行以下任务:
Make a predicate A(P,N,L)
such that for all C
which is nth element of L
, P(N,C)
.
基本上我想在范围 [0..N]
上执行映射。
在Haskell,我最熟悉的语言中,这看起来像
f p n = map(p)[0..n]
(Haskell 没有谓词所以我在这里采取一些自由)
或在 pointfree 中
f = (.enumFromTo 0).map
看来我应该能够很容易地在 Prolog 中完成它。 Prolog 的 maplist/3
基本上已经是这样,所以它应该是一个微不足道的修改。我的定义应该类似于:
A(P,N,L) :- maplist(P, ??? , L).
但是我实在想不出要在空白处填什么。在 Haskell 中我会使用像 enumFromTo
这样的函数,但在 Prolog 中似乎不存在这样的东西。关闭等效项是 between/3
,但这不是列表,所以我不能用于 maplist
.
或者我可以创建自己的范围谓词。
我首先尝试的是:
range(0,[0]).
range(N,[N|T]) :- range(N-1,T).
A(P,N,L) :- range(N,rangeN), maplist(P, rangeN, L).
但我根本无法解决这个问题。我也试过了
range(N,L):-findall(X,between(0,N,X),L),sort(L,L).
A(P,N,L) :- range(N,rangeN), maplist(P, rangeN, L).
但对于这么小的问题,这似乎真的很笨拙。
我如何填补 maplist
中的空白?我是不是以错误的方式解决了问题?
-- % f p n = map (p) [0..n] = [p 0, p 1, p 2, ..., p n]
被翻译成 Prolog 为
f(P,N,L):- f(P,0,N,L).
f(P,I,N,[]):- I > N.
f(P,I,N,L):- call(P,I,X),
( N =:= I -> L = [X]
; L = [X|T], J is I+1, f(P,J,N,T) ).
这假设 a
为 p :: Int -> a
,正如 Haskell 代码所暗示的那样。
这还假设您获得了一个具体的 ("ground") 可调用双参数谓词 P
和一个整数 N
.
另一种可能是
g(P,N,L):- findall(X, (between(0, N, I), call(P,I,X)), L).
这会找到所有 X
满足 (0 <= I <= N
and P(I,X)
) 成立。
在 SWI-Prolog 中测试:
11 ?- [user].
add1(X,Y):- Y is X+1.
|:
12 ?- f(add1,5,L).
L = [1, 2, 3, 4, 5, 6].
13 ?- g(add1,5,L).
L = [1, 2, 3, 4, 5, 6].
当我尝试在 Prolog 中编写 N 皇后问题的解决方案时,如 Picat 主页所述(参见示例 5,接近页面末尾),我遇到了类似的问题。这是我的最终结果,并评论了一些备选方案:
:- use_module(library(clpfd)).
queens(N, Q) :-
length(Q, N),
Q ins 1..N,
all_different(Q),
maplist_index([I,V,P]>>(P#=V+I),1,Q,Ps),all_different(Ps),
maplist_index([I,V,M]>>(M#=V-I),1,Q,Ms),all_different(Ms),
/* no
bagof(P, (nth1(I,Q,V), P #= V + I), Ps), all_different(Ps),
bagof(M, (nth1(I,Q,V), M #= V - I), Ms), all_different(Ms),
*/
/* ok
all_different_p(Q, 1, P), all_different(P),
all_different_m(Q, 1, M), all_different(M),
*/
label(Q).
all_different_p([Q|Qs], I, [P|Ps]) :-
P #= Q + I,
succ(I, J),
all_different_p(Qs, J, Ps).
all_different_p([], _I, []).
all_different_m([Q|Qs], I, [P|Ps]) :-
P #= Q - I,
succ(I, J),
all_different_m(Qs, J, Ps).
all_different_m([], _I, []).
maplist_index(P, I, [X|Xs], [Y|Ys]) :-
call(P, I, X, Y),
succ(I, J),
maplist_index(P, J, Xs, Ys).
maplist_index(_, _, [], []).
maplist_index/4 是您需要的示例。值得注意的是 bagof/3 在存在属性变量的情况下效果不佳。
我刚开始使用 Prolog,我希望执行以下任务:
Make a predicate
A(P,N,L)
such that for allC
which is nth element ofL
,P(N,C)
.
基本上我想在范围 [0..N]
上执行映射。
在Haskell,我最熟悉的语言中,这看起来像
f p n = map(p)[0..n]
(Haskell 没有谓词所以我在这里采取一些自由)
或在 pointfree 中
f = (.enumFromTo 0).map
看来我应该能够很容易地在 Prolog 中完成它。 Prolog 的 maplist/3
基本上已经是这样,所以它应该是一个微不足道的修改。我的定义应该类似于:
A(P,N,L) :- maplist(P, ??? , L).
但是我实在想不出要在空白处填什么。在 Haskell 中我会使用像 enumFromTo
这样的函数,但在 Prolog 中似乎不存在这样的东西。关闭等效项是 between/3
,但这不是列表,所以我不能用于 maplist
.
或者我可以创建自己的范围谓词。
我首先尝试的是:
range(0,[0]).
range(N,[N|T]) :- range(N-1,T).
A(P,N,L) :- range(N,rangeN), maplist(P, rangeN, L).
但我根本无法解决这个问题。我也试过了
range(N,L):-findall(X,between(0,N,X),L),sort(L,L).
A(P,N,L) :- range(N,rangeN), maplist(P, rangeN, L).
但对于这么小的问题,这似乎真的很笨拙。
我如何填补 maplist
中的空白?我是不是以错误的方式解决了问题?
-- % f p n = map (p) [0..n] = [p 0, p 1, p 2, ..., p n]
被翻译成 Prolog 为
f(P,N,L):- f(P,0,N,L).
f(P,I,N,[]):- I > N.
f(P,I,N,L):- call(P,I,X),
( N =:= I -> L = [X]
; L = [X|T], J is I+1, f(P,J,N,T) ).
这假设 a
为 p :: Int -> a
,正如 Haskell 代码所暗示的那样。
这还假设您获得了一个具体的 ("ground") 可调用双参数谓词 P
和一个整数 N
.
另一种可能是
g(P,N,L):- findall(X, (between(0, N, I), call(P,I,X)), L).
这会找到所有 X
满足 (0 <= I <= N
and P(I,X)
) 成立。
在 SWI-Prolog 中测试:
11 ?- [user]. add1(X,Y):- Y is X+1. |: 12 ?- f(add1,5,L). L = [1, 2, 3, 4, 5, 6]. 13 ?- g(add1,5,L). L = [1, 2, 3, 4, 5, 6].
当我尝试在 Prolog 中编写 N 皇后问题的解决方案时,如 Picat 主页所述(参见示例 5,接近页面末尾),我遇到了类似的问题。这是我的最终结果,并评论了一些备选方案:
:- use_module(library(clpfd)).
queens(N, Q) :-
length(Q, N),
Q ins 1..N,
all_different(Q),
maplist_index([I,V,P]>>(P#=V+I),1,Q,Ps),all_different(Ps),
maplist_index([I,V,M]>>(M#=V-I),1,Q,Ms),all_different(Ms),
/* no
bagof(P, (nth1(I,Q,V), P #= V + I), Ps), all_different(Ps),
bagof(M, (nth1(I,Q,V), M #= V - I), Ms), all_different(Ms),
*/
/* ok
all_different_p(Q, 1, P), all_different(P),
all_different_m(Q, 1, M), all_different(M),
*/
label(Q).
all_different_p([Q|Qs], I, [P|Ps]) :-
P #= Q + I,
succ(I, J),
all_different_p(Qs, J, Ps).
all_different_p([], _I, []).
all_different_m([Q|Qs], I, [P|Ps]) :-
P #= Q - I,
succ(I, J),
all_different_m(Qs, J, Ps).
all_different_m([], _I, []).
maplist_index(P, I, [X|Xs], [Y|Ys]) :-
call(P, I, X, Y),
succ(I, J),
maplist_index(P, J, Xs, Ys).
maplist_index(_, _, [], []).
maplist_index/4 是您需要的示例。值得注意的是 bagof/3 在存在属性变量的情况下效果不佳。