这段代码的意思和作用是什么?

时间:2015-11-02 10:03:01

标签: list prolog

我是Prolog的新手,我无法理解这段代码。你会如何阅读这4个条款?他们在做什么?

a([]). 
a([_|L]):-b(L).

b([_]).
b([_|L]):-a(L).

谢谢。

2 个答案:

答案 0 :(得分:1)

参数模式很重要:

a)清单显然是一个反击,因为我们从不考虑内容。

b)只是一个建议:将逻辑读作制作,或作为DCG

a-->[];[_],b.
b-->[_];[_],a.

被调用 - 例如

?- phrase(a, [w,h,a,t]).

答案 1 :(得分:1)

正如@repeat在评论中建议的那样,运行一般查询,这就是你得到的:

| ?- a(Xs).

Xs = [] ? ;

Xs = [_,_] ? ;

Xs = [_,_] ? ;

Xs = [_,_,_,_] ? ;

Xs = [_,_,_,_] ? ;

Xs = [_,_,_,_,_,_] ? ;

Xs = [_,_,_,_,_,_] ? ;
...

| ?- b(Xs).

Xs = [_] ? ;

Xs = [_] ? ;

Xs = [_,_,_] ? ;

Xs = [_,_,_] ? ;

Xs = [_,_,_,_,_] ? ;

Xs = [_,_,_,_,_] ? ;

Xs = [_,_,_,_,_,_,_] ? ;

Xs = [_,_,_,_,_,_,_] ? ;
...

如果a(Xs)是包含偶数个元素的列表,则Xs成功;如果b(Xs)是包含奇数个参数的列表,则Xs成功。a/1成功。正如您所看到的,b/1a([]).在每种情况下都会成功两次,除了even([]). even([_|L]) :- odd(L). odd([_]). odd([_|L]) :- even(L). 只会成功一次。因此,它不是确定列表长度奇偶校验的有效谓词。

让我们用更具描述性的名称重写这些:

[]

现在让我们“读”他们所说的话:

  1. [_|L]是一个偶数列表
  2. 如果L是奇数列表,则
  3. [_]是偶数列表
  4. [_|L]是一个奇怪的列表
  5. 如果L是偶数列表,
  6. even/1是一个奇怪的列表
  7. 这些听起来合乎逻辑,但为什么odd/1even([])成功完成两次odd/1除外?如果您查看[_]的定义,odd([_]).有两种方法可以成功。一个是通过odd/1条款。第二个是第二个odd([_|[]]) :- even([]). % [_] == [_|[]] ,因为你有:

    even/1

    由于odd/1even([]).调用(odd([_])除外)最终会向下调用even([]). even([_,_|L]) :- even(L). odd([_]). odd([_,_|L]) :- odd(L). ,因此您将获得两个解决方案。

    <小时/> 消除逻辑中模糊性的一种方法是稍微重构它们。请考虑以下递归规则:

    • 如果列表的尾部在前2个之后也是偶数,则至少2个元素的列表具有偶数个元素。
    • 如果列表的尾部在前2个之后也是奇数,则至少2个元素的列表具有奇数个元素。

    将这些规则翻译成Prolog,包括以前的基本案例:

    | ?- even(Xs).
    
    Xs = [] ? ;
    
    Xs = [_,_] ? ;
    
    Xs = [_,_,_,_] ? ;
    
    Xs = [_,_,_,_,_,_] ? ;
    ...
    

    现在结果将是:

    | ?- odd(Xs).
    
    Xs = [_] ? ;
    
    Xs = [_,_,_] ? ;
    
    Xs = [_,_,_,_,_] ? ;
    ...
    

    even --> [] | [_,_], even.
    odd --> [_] | [_,_], odd.
    

    根据CapelliC建议使用DCG,可以写出类似的规则:

    | ?- phrase(even, L).
    
    L = [] ? ;
    
    L = [_,_] ? ;
    
    L = [_,_,_,_] ? ;
    ...
    

    结果:

    | ?- phrase(odd, L).
    
    L = [_] ? ;
    
    L = [_,_,_] ? ;
    
    L = [_,_,_,_,_] ? ;
    ...
    

    odd([_]).

    <小时/> 遵循@ false的建议,对原始代码进行更直接的“修复”将消除even([]).的冗余基本情况,因为它已经被even/1的基本情况所涵盖。这也有点简单比上述解决方案更好,因为它利用了odd/1even/1谓词之间的相互依赖关系(在上面的解决方案中,odd/1even([]). even([_|L]) :- odd(L). odd([_|L]) :- even(L). 独立存在)。

    even --> [] | [_], odd.
    odd --> [_], even.
    

    或者,在DCG:

    # ~/.tmuxinator/dyn.yml
    
    name: dyn
    root: ~/
    windows:
      # just using `echo` as a POC; this is where you'd make your function call
      <%- `echo "111,222,333"`.split(',').each do |ip| %>
      - tunnel-to-<%= ip.chomp %>: echo tunnel_to <%= ip %>
      <%- end %>