首页 文章

请解释这个用Prolog编写的图灵机模拟器

提问于
浏览
8

Wikipedia Prolog article包括此图灵机模拟器:

turing(Tape0, Tape) :-
    perform(q0, [], Ls, Tape0, Rs),
    reverse(Ls, Ls1),
    append(Ls1, Rs, Tape).

perform(qf, Ls, Ls, Rs, Rs) :- !.
perform(Q0, Ls0, Ls, Rs0, Rs) :-
    symbol(Rs0, Sym, RsRest),
    once(rule(Q0, Sym, Q1, NewSym, Action)),
    action(Action, Ls0, Ls1, [NewSym|RsRest], Rs1),
    perform(Q1, Ls1, Ls, Rs1, Rs).

symbol([], b, []).
symbol([Sym|Rs], Sym, Rs).

action(left, Ls0, Ls, Rs0, Rs) :- left(Ls0, Ls, Rs0, Rs).
action(stay, Ls, Ls, Rs, Rs).
action(right, Ls0, [Sym|Ls0], [Sym|Rs], Rs).

left([], [], Rs0, [b|Rs0]).
left([L|Ls], Ls, Rs, [L|Rs]).

它给出了一个示例程序:

  • 在读取"1"时,向右移动头部 .

  • 在读取空白时,写入一个并进入最终状态 .

程序:

rule(q0, 1, q0, 1, right).
rule(q0, b, qf, 1, stay).

该程序如下所示运行:

?- turing([1,1,1], Ts).
Ts = [1, 1, 1, 1] ;

我理解规则/事实中一些变量名称的含义:

turing(Tape0, Tape)

  • tape0是输入磁带

  • tape是输出磁带

rule(Q0, Sym, Q1, NewSym, Action)

  • Q0:开始状态

  • Sym:符号读取

  • Q1:结束状态

  • NewSym:要写的符号

  • 动作:如何移动头部

我不明白这些规则/事实中变量的含义:

perform(Q0, Ls0, Ls, Rs0, Rs)

symbol([Sym|Rs], Sym, Rs)

action(left/stay/right, Ls0, Ls, Rs0, Rs)

left([L|Ls], Ls, Rs, [L|Rs])

谁有人解释一下?

1 回答

  • 3

    在图灵机中,在任何给定状态下,写头指向磁带上的特定位置 . 头部左侧会有符号,头部会有符号 .

    看第一个主谓词:

    turing(Tape0, Tape) :-
        perform(q0, [], Ls, Tape0, Rs),
        reverse(Ls, Ls1),
        append(Ls1, Rs, Tape).
    

    它将通过调用 perform/5 来"run the machine" . perform(Q0, Ls0, Ls, Rs0, Rs) 的参数表示:

    Q0 - the current state (or initial state before the "perform")
    Ls0 - the current set of symbols that are LEFT of the head
    Ls - the FINAL set of symbols that WILL BE left of the head after perform
    Rs0 - the current set of symbols that are RIGHT of the head
    Rs - the FINAL set of symbols that WILL BE right of the head after perform
    

    最初,头部没有符号 . Tape0 最初包含头部右侧的所有符号 . 要"run the machine",主谓词调用:

    perform(Q0, [], Ls, Tape0, Rs)
    

    它从初始状态 Q0 开始,头部没有符号( [] ),并且头部右侧的符号在 Tape0 中开始 . 在查询完成时,期望 Ls 实例化头部左边的最后一组符号,并且 Rs 是头部右边的最后一组符号 .

    其他所有东西现在都支持 perform/5 .

    symbol([Sym|Rs], Sym, Rs)
    

    这定义了符号列表 [Sym|Rs] 与该列表中的第一个符号( Sym )和列表的其余部分( Rs )之间的关系 . perform/5 使用此谓词来读取当前位于头部右侧的下一个符号 .

    为了使其在使用的上下文中正常工作, perform/5 谓词维护 Rs0 变量,使其正确顺序,其中列表的头部是右边的第一个符号,列表的第二个元素是以下符号在右边,等等 . 请注意,这不是左侧符号列表的情况 . 左侧列表的维护顺序与符号在磁带上的显示方式相反 . 原因是它们可以按当前头部位置的剩余距离来考虑 . 稍后更多关于这一点 .

    action(left/stay/right, Ls0, Ls, Rs0, Rs)
    

    这就是行动的所在 . :)在采取一个动作之后,新头部位置的左右两侧's role is to perform the given action and provide the correctly updated lists of what' . 在执行操作之前, Ls0Rs0 分别是头部左侧和右侧的符号列表 . 并且 LsRs 分别是执行动作后头部左右的符号 .

    action(stay, Ls, Ls, Rs, Rs).
    

    这个动作说当我留下时,头部左侧和右侧的符号不会改变 .

    action(right, Ls0, [Sym|Ls0], [Sym|Rs], Rs).
    

    这个动作表示当我将头部向右移动一个符号位置时,右边的符号(自右边符号集为 [Sym|Rs] 后为 Sym )成为左边的符号 . 左边的符号集最初为 Ls0 ,变为 [Sym|Ls0] . 右边的符号列表最初为 [Sym|Rs] ,变为 Rs .

    left 动作比 stayright 稍微复杂一点,因为当左侧没有更多符号并且指示向左移动时,头部仍向左移动并且右侧出现空白 . 所以 left 它被分解成一个单独的小谓词:

    action(left, Ls0, Ls, Rs0, Rs) :- left(Ls0, Ls, Rs0, Rs).
    
    left([], [], Rs0, [b|Rs0]).
    

    这里,如果左边的一组符号是空的( [] ),那么向左移动意味着左边的符号保持为空( [] ),并且在头部右边出现一个新的空白( b ),位于原始右边符号集的头部(右侧列表从 Rs0 变为 [b|Rs0] ) .

    left([L|Ls], Ls, Rs, [L|Rs]).
    

    这里左边有一些符号,动作是向左移动 . 左边的初始符号集是 [L|Ls]L 是头部左侧的符号),头部右边的初始符号集是 Rs . 当头向左移动时,左边的第一个符号成为右边的第一个符号 . 因此更新的左符号集是 Ls ,更新的右符号集是 [L|Rs] .

    action(left, ...) 谓词可能是在没有辅助谓词的情况下编写的, left/4 ,这样:

    action(left, [], [], Rs0, [b|Rs0]).
    action(left, [L|Ls], Ls, Rs, [L|Rs]).
    

    返回左侧列表和原始 turing/2 谓词:在 turing/2 调用 perform(q0, [], Ls, Tape0, Rs) 之后,它在右侧( Rs )有一组最终符号,这些符号的顺序是从左到右 . 但是,左边的最后一组符号( Ls )从右到左列出(因为它们与当前头部位置的接近程度) . 因此,为了以正确的顺序显示整个磁带,左侧列表必须反转符号,然后将其添加到正确的符号集之前 . 因此,电话:

    reverse(Ls, Ls1),
    append(Ls1, Rs, Tape).
    

    分解 perform/5 谓词:

    perform(qf, Ls, Ls, Rs, Rs) :- !.
    

    这表示如果我们处于最终状态 qf ,那么左符号的最终列表 Ls 将成为我们当前的左符号集 . 同样适用于正确的符号 .

    perform(Q0, Ls0, Ls, Rs0, Rs) :-
        % Read the symbol to the right of the head (Sym)
        %
        symbol(Rs0, Sym, RsRest),
    
        % Apply first found matching rule to the current state (Q0)
        %   and the current symbol on the right (Sym), resulting in
        %   a new symbol (NewSym) and an action (Action)
        %
        once(rule(Q0, Sym, Q1, NewSym, Action)),
    
        % Perform the action using the current list of symbols on the left (Ls0)
        %  and the updates list of symbols on the right (old right symbol (Sym)
        %  replaced by the new right symbol (NewSym), which is [NewSym|RsRest]
        %  with the action resulting in new left Ls1 and new right Ls2
        %  sets of symbols
        %
        action(Action, Ls0, Ls1, [NewSym|RsRest], Rs1),
    
        % Recursively perform the Turing engine on the new state, left,
        %  and right sets of symbols until we hit the final state (qf)
        %  with final result being left symbols, Ls, and right symbols, Rs
        %
        perform(Q1, Ls1, Ls, Rs1, Rs).
    

相关问题