【问题标题】:Generate all words of length N and form a list with them in Prolog生成所有长度为 N 的单词并在 Prolog 中与它们形成一个列表
【发布时间】:2020-01-04 12:12:28
【问题描述】:

给定字母 [a, b, c] 生成包含由这些字母组成的所有长度为 N 的单词的列表。 例如:

?- generate(2, L).

应该输出:

L = [aa, ab, ac, ba, bb, bc, ca, cb, cc]。

起初,这似乎是一个非常简单的问题,但我发现我的实现都不起作用。

这是第二个实现,一种有效的实现。

letter(X) :- member(X, [a, b, c]).

generateWord(0, []) :- !.
generateWord(N, [H|T]) :-
    letter(H), 
    NextN is N - 1,
    generateWord(NextN, T).

generateAtomicWord(N, Word) :-
    generateWord(N, WList),
    atomic_list_concat(WList, Word).

maxSolutions(N, R) :- R is N ** 3.

generate(N, CurrentList, ResultList) :-
    maxSolutions(N, R), 
    length(CurrentList, L),
    L =:= R, 
    append(CurrentList, [], ResultList), !.
generate(N, CurrentList, ResultList) :-
    generateAtomicWord(N, NewWord),
    \+ member(NewWord, CurrentList),
    append(CurrentList, [NewWord], NewList),
    generate(N, NewList, ResultList).

generate(N, ResultList) :- 
    generate(N, [], ResultList).

有点工作,因为当给定 N = 3 时,程序输出:

L = [aaa, aab, aac, aba, abb, abc, aca, acb, acc|...]

我的第一个实现是不同的,但我无法让它在任何情况下都起作用。

letter(X) :- member(X, [a, b, c]).

generateWord(0, []) :- !.
generateWord(N, [H|T]) :-
    letter(H), 
    NextN is N - 1,
    generateWord(NextN, T), !.

generateAtomicWord(N, Word) :-
    generateWord(N, WList),
    atomic_list_concat(WList, Word).

maxSolutions(N, R) :- R is N ** 3.

generate(N, [H]) :- generateAtomicWord(N, H).
generate(N, [H|T]) :- 
    generate(N, T),
    length(T, TailLen), 
    maxSolutions(N, M), 
    (TailLen =:= M -> !; 
        generateAtomicWord(N, H),
        \+ member(H, T)).

这只是输出:

L = [aa]

当请求其余解决方案时,它会循环。

必须在不使用谓词的情况下解决问题,例如:

findall、findsol、bagof、setof 等...

找到所有解决方案。

我添加了标签 backtracking 因为它确实类似于回溯问题,但我不知道 Prolog 中的标准实现可能是什么样的。

【问题讨论】:

  • 请提供更多关于本练习的具体背景的信息。

标签: prolog backtracking


【解决方案1】:

这很有效,因为当给定 N = 3 时,程序输出:

L = [aaa, aab, aac, aba, abb, abc, aca, acb, acc|...]

这不是错误,而是 Prolog 解释器以更短的方式显示列表。如果在显示输出时点击 w,它将显示完整列表。如需更多信息,请参阅this answer

话虽如此,你也太难了。您可以首先创建一个谓词,将变量与所有可能的原子统一起来:

letter(X) :- member(X, [a, b, c]).

word(0, []).
word(N, [C|W]) :-
    N > 0,
    N1 is N-1,
    letter(C),
    word(N1, W).

现在我们可以使用findall/3 [swi-doc] 生成所有可能性,例如使用maplist/3 [swi-doc]atomic_list_concat/2 将列表转换为单个原子:

words(N, L) :-
    findall(W, word(N, W), Ws),
    maplist(atomic_list_concat, Ws, L).

例如:

?- words(0, L).
L = [''].

?- words(1, L).
L = [a, b, c].

?- words(2, L).
L = [aa, ab, ac, ba, bb, bc, ca, cb, cc].

?- words(3, L).
L = [aaa, aab, aac, aba, abb, abc, aca, acb, acc|...].

我们可以通过更新“差异”列表来自己生成列表列表,直到生成所有可能的单词:

wordlist(N, L) :-
    wordlist(N, [], L, []).

wordlist(0, R, [W|T], T) :-
    reverse(R, W),
    !.
wordlist(N, C, L, T) :-
    N > 0,
    N1 is N-1,
    wordfold([a,b,c], N1, C, L, T).

wordfold([], _, _, L, L).
wordfold([C|CS], N1, CT, L, T) :-
    wordlist(N1, [C|CT], L, L2),
    wordfold(CS, N1, CT, L2, T).

例如:

?- wordlist(0, L).
L = [[]].

?- wordlist(1, L).
L = [[a], [b], [c]].

?- wordlist(2, L).
L = [[a, a], [a, b], [a, c], [b, a], [b, b], [b, c], [c, a], [c|...], [...|...]].

然后您仍然需要对其执行atomic_list_concat。我把它留作练习。

【讨论】:

  • 我忘了指定,但我不允许使用 findAll
  • @CosminStoian:这不是什么大问题。尝试做一些可以收集结果的东西:)
  • 这就是我在第一个实现中尝试做的事情,但我绝对不喜欢 prolog。我将在您的实施中尝试更多。谢谢!
  • 如果没有findAll,除了手动计算最大解的个数,还有其他方法可以停止执行程序吗?
  • @CosminStoian:是的,您可以使用通过可能的解决方案建立的差异列表。
猜你喜欢
  • 2019-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多