我想在我的DCG语法中添加print
命令,这是我的内容:
program( (R0 --> R) ) -->
[begin],instructs(( R0 --> R )),[end].
instructs( ( R0 --> R ) ) -->
instr(( R0 --> R )).
instructs( ( R0 --> R ) ) -->
instr(( R0 --> R1 )),
instructs(( R1 --> R )).
instr( ( R0 --> R ) ) -->
[ dte], { R is 2*R0}.
instr( ( R0 --> R ) ) -->
[ dto], { R is 2*R0 + 1}.
instr( ( R0 --> R ) ) -->
[ halve], { R is R0 // 2}.
要添加print
,我需要将R0 --> R
更改为R0 --> OutTape
,其中OutTape
是该计划的输出。
我以为我可以做到以下几点:
program( (R0 --> OutTape) ) -->
[begin],instructs(( R --> Tape )),[end].
instructs( ( R --> Tape ) ) -->
instr(( R --> Tape )).
instructs( ( R --> Tape ) ) -->
instr(( R --> Tape)),
instructs(( R --> Tape )).
instr( ( R --> Tape ) ) -->
[ dte], { R is 2*R}. % is this a legal term?
instr( ( R --> Tape ) ) -->
[ dto], { R is 2*R + 1}.
instr( ( R --> Tape ) ) -->
[ halve], { R is R // 2}.
instr( ( R --> Tape ) ) -->
[ print], {append()}. % how to append R to Tape?
但我不知道如何将R附加到磁带上,请你指引我走向正确的方向?
答案 0 :(得分:3)
在Prolog中,您无法重新分配变量。因此,R is R // 2
之类的表达式会失败,因为在Prolog中,它在语义上说* R
本身是整数除2
,只有在R
为0时才会为真。
同样,假设Tape
是列表,则无法继续附加到同一列表(或磁带)。您必须提供磁带的先前状态,然后在打印到磁带后提供新状态。这需要在谓词中添加一个额外的参数来表示先前的磁带状态。在开始时,磁带为空,因此先前状态为[]
。
此外,虽然在您的问题中没有完全解释,但您可能希望将中间结果“打印”到磁带上。这意味着您还需要携带中间结果,以便在遇到print
指令时可以将其“打印”到磁带上。那将是另一个论点。
program((R0 --> Tape)) -->
% Initially, the tape is empty: []
% OutTape is needed here, not "Tape" as originally shown
% The second argument of `instructs` will have the final value,
% but we'll use `_` here since we only care about the values
% "printed" to the `OutTape`
[begin], instructs((R0 --> OutTape), _, []), [end], { reverse(OutTape, Tape) }.
instructs((R0 --> Tape), R, PrevTape) -->
instr((R0 --> Tape), R, PrevTape).
instructs((R0 --> Tape), R, PrevTape) -->
instr((R0 --> NextTape), R1, PrevTape), % NextTape is an intermediate tape state
instructs((R1 --> Tape), R, NextTape).
instr((R0 --> PrevTape), R, PrevTape ) -->
[dte], { R is 2*R0 }.
instr((R0 --> PrevTape), R, PrevTape) -->
[dto], { R is 2*R0 + 1 }.
instr((R0 --> PrevTape), R, PrevTape) -->
[halve], { R is R0 // 2 }.
instr((R --> [R|PrevTape]), R, PrevTape) -->
[print].
另外,在上面的代码中,我使用reverse
作为一种快速的方法,将磁带按顺序从左到右,尽管我不确定这是否符合您的要求。
| ?- phrase(program((3 --> Tape)), [begin, dte, dto, print, dte, print, end], []).
Tape = [13,26] ? ;
(1 ms) no
| ?-
<小时/> 结语
在此上下文中使用-->
作为参数的函子,虽然在语法上是允许的,但有点不寻常,可能会令人困惑。使用逗号会更加规范:
program(R0, Tape) -->
% Initially, the tape is empty: []
% OutTape is needed here, not "Tape" as originally shown
% The 3rd argument of `instructs` will have the final value,
% but we'll use `_` here since we only care about the values
% "printed" to the `OutTape`
[begin], instructs(R0, OutTape, _, []), [end], { reverse(OutTape, Tape) }.
instructs(R0, Tape, R, PrevTape) -->
instr(R0, Tape, R, PrevTape).
instructs((R0, Tape, R, PrevTape) -->
instr(R0, NextTape, R1, PrevTape), % NextTape is an intermediate tape state
instructs(R1, Tape, R, NextTape).
instr(R0, PrevTape, R, PrevTape ) -->
[dte], { R is 2*R0 }.
instr(R0, PrevTape, R, PrevTape) -->
[dto], { R is 2*R0 + 1 }.
instr(R0, PrevTape, R, PrevTape) -->
[halve], { R is R0 // 2 }.
instr(R, [R|PrevTape], R, PrevTape) -->
[print].