我想声明一个列表列表,如下所示:
%% example 1
Xs = [
[[A],[[A]]],
[[A],[[A],[A]]],
[[A],[[A],[A],[A]]]
].
这里,符号A
指的是每个列表中的相同变量。执行maplist(writeln,xs)会产生以下输出:
[[_G1],[[_G1]]]
[[_G1],[[_G1],[_G1]]]
[[_G1],[[_G1],[_G1],[_G1]]]
我想在每个列表中使用相同的符号A
,但是为了使每个列表的变量不同,要提供以下输出:
[[_G1],[[_G1]]]
[[_G2],[[_G2],[_G2]]]
[[_G3],[[_G3],[_G3],[_G3]]]
我做这项工作的唯一方法是为每个列表提供自己唯一的变量,如下所示:
%% example 2
Xs = [
[[A1],[[A1]]],
[[A2],[[A2],[A2]]],
[[A3],[[A3],[A3],[A3]]]
].
是否有任何Prolog语法,因此不需要为每个变量编号,如示例2所示?我尝试在列表中添加括号,如下所示:
Xs = [
([[A],[[A]]]),
([[A],[[A],[A]]]),
([[A],[[A],[A],[A]]])
].
但是这给了我与例1相同的输出。
答案 0 :(得分:2)
你可以这样做:
首先,使用不同的变量创建所需的列表结构:
?- maplist(length, Lists, [2,3,4]).
Lists = [[X1, X2], [X3, X4, X5], [X6, X7, X8, X9]].
然后,使用以下附加定义:
same_element(Ls) :- maplist(=([_]), Ls).
您可以将同一子列表中的变量统一到同一个词:
?- maplist(same_element, [[X1, X2], [X3, X4, X5], [X6, X7, X8, X9]]).
X1 = X2, X2 = [_G1141],
X3 = X4, X4 = X5, X5 = [_G1149],
X6 = X7, X7 = X8, X8 = X9, X9 = [_G1157].
组合:
?- maplist(length, Lists, [2,3,4]),
maplist(same_element, Lists),
maplist(writeln, Lists).
得到以下特性:
[[_G1079],[_G1079]]
[[_G1087],[_G1087],[_G1087]]
[[_G1095],[_G1095],[_G1095],[_G1095]]
现在,使用以下Emacs定义:
(defun nice-variables (start end)
(interactive "r")
(goto-char start)
(let ((n 1)
(variables nil)
(m (make-marker)))
(set-marker m end)
(while (and (<= (point) (marker-position m))
(re-search-forward "_G" (marker-position m) t))
(let* ((from (point))
(len (skip-chars-forward "0-9"))
(str (buffer-substring-no-properties from (+ from len)))
(num (assoc str variables)))
(delete-backward-char (+ len 2))
(if num
(insert (format "X%d" (cdr num)))
(setq variables (cons (cons str n) variables))
(insert (format "X%d" n))
(setq n (1+ n)))))))
在该地区和M-x nice-variables RET
,您得到:
[[X1],[X1]]
[[X2],[X2],[X2]]
[[X3],[X3],[X3],[X3]]
这也是我在上面第一个查询的输出中使用的,以使其更具可读性。
因此,您可以通过统一想要相同的变量来生成动态所需的结构,或者复制&amp;粘贴上面的输出并直接在程序中稍作修改即可使用它。
答案 1 :(得分:2)
Prolog中的变量名称具有跨越谓词定义中的单个子句或顶级查询的作用域。所以,这个:
?- List = [A, A, A].
表示具有相同变量A
的三倍的列表。如果你把它放到一个谓词中,那就像在一个文件中my_lists.pl
(我没有像你一样嵌套列表,只是为了保持简单):
my_list([A, A]).
my_list([A, A, A]).
my_list([A, A, A, A]).
三个子句中的A
现在不在同一个词法范围内,因此如果您查阅此谓词,然后使用例如my_list(L)
收集findall/3
的所有可能实例,你得到你想要的东西:
?- [my_lists].
true.
?- findall(L, my_list(L), Ls).
Ls = [[_G1945, _G1945],
[_G1933, _G1933, _G1933],
[_G1918, _G1918, _G1918, _G1918]].
这接近你想要的吗?你想要实现的是什么?
答案 2 :(得分:2)
如果要写出变量并为它们指定精确的名称,则需要写选项variable_names/1
。 This answer解释了如何。或者,您可以使用遗留谓词numbervars/3
,使用术语'$VAR'(N)
统一不同的变量,然后使用writeq/1
或写选项numbervars(true)
。
但是在您指出的情况下,这两种方法都不起作用。事实上,你的查询真的很幸运
?- Xs = [[[A],[A]],[[A],[A],[A]],[[A],[A],[A],[A]]], maplist(writeln,Xs).
为不同的列表生成相同的变量。更糟糕的是,编写相同列表的目标非常相同,可能会为不同的调用生成不同的变量名称:
p(N) :-
length(_,N),
length(K,1),
writeq(K),
garbage_collect,
writeq(K).
对于p(100)
,SICStus写入[_776][_46]
,SWI写入[_G517][_G3]
。简而言之,你在美好的一天抓住了Prolog。这并不奇怪,因为标准只需要依赖于&#34;实现依赖&#34;具有一些限制的名称的值:它以下划线开头,其余字符对于不同的变量是不同的,对于相同的写入目标中的相同变量也是如此。以下是ISO / IEC 13211-1:1995:
7.10.5写一个术语
使用
Term
(8.14.2)输出术语write_term/3
时 所采取的行动由以下规则界定:
a)如果
Term
是变量,则表示字符序列 发送该变量是输出。序列开始了 带_(下划线),其余字符为
依赖于实现。相同的字符序列
用于每次出现的特定变量Term
。每个字符使用不同的字符序列Term
中的不同变量。
这样做的原因是全局一致的变量命名会在实现中产生大量开销。
总结:如果要为同一个变量使用不同的变量名,请使用带有不同参数的variable_names/1
。如果您希望变量实际上不同,请以不同方式命名,或相应地使用copy_term/2
。