1

我想声明一个列表列表,如下所示:

%% 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 相同的输出。

4

3 回答 3

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]]

这也是我在上面第一个查询的输出中使用的,以使其更具可读性。

因此,您可以通过统一您希望相同的变量动态生成所需的结构,或者复制并粘贴上面的输出并直接在您的程序中稍作修改使用它。

于 2014-11-10T06:47:30.673 回答
2

如果要写出变量并为它们指定精确的名称,则需要 write-option variable_names/1这个答案解释了如何。numbervars/3或者,您可以使用将不同变量与 term 统一的遗留谓词'$VAR'(N),然后使用writeq/1or 或 write-option 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。这并不奇怪,因为标准只要求名称的“实现依赖”值有一些限制:它以下划线开头,其余字符对于不同的变量是不同的,对于同一个变量的相同写入相同目标。这是 ISO/IEC 13211-1:1995 的相关标准:

7.10.5 写一个术语

当使用(8.14.2)Term输出术语时 ,所采取的操作由以下规则定义:write_term/3

a) 如果Term是变量,
则输出表示该变量的字符序列。该序列
以 _(下划线)开头,其余字符
取决于实现。相同的字符序列
用于 中的特定变量的每次出现
Term。中的每个
不同变量使用不同的字符序列Term

原因是全局一致的变量命名会在实现中产生大量开销。

总结一下:如果你想为同一个变量使用不同的变量名,那么使用variable_names/1不同的参数。如果您希望变量实际上有所不同,请以不同的方式命名它们,或copy_term/2相应地使用它们。

于 2014-11-10T10:01:57.953 回答
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]).

三个子句中的As 现在不在同一个词法范围内,所以如果你查阅这个谓词,然后收集所有可能的my_list(L)使用实例,例如findall/3,你会得到你想要的:

?- [my_lists].
true.

?- findall(L, my_list(L), Ls).
Ls = [[_G1945, _G1945],
      [_G1933, _G1933, _G1933],
      [_G1918, _G1918, _G1918, _G1918]].

这是否接近您正在寻找的内容?你想达到什么目的?

于 2014-11-10T06:52:48.300 回答