Data structures 在Prolog中创建队列结构
我正在学习Prolog,在学习面向对象的语言时遇到了困难 我试图完成以下说明: 实现分阶段队列。这是一个由两个列表组成的结构: 前端和后端,表示为Data structures 在Prolog中创建队列结构,data-structures,prolog,queue,structure,custom-data-type,Data Structures,Prolog,Queue,Structure,Custom Data Type,我正在学习Prolog,在学习面向对象的语言时遇到了困难 我试图完成以下说明: 实现分阶段队列。这是一个由两个列表组成的结构: 前端和后端,表示为队列(前端、后端)。这个 如果两个列表都为空,则队列为空。如果将元素添加到 将它们添加到后端的队列;如果它们被移除,它们将被移除 从前端移除;如果前端变空(且 后端不为空)则后端将成为具有[] 作为新的后端。例如,我们可以从如下队列开始 队列([2,5,7],]),添加8将为我们提供队列([2,5,7],[8]),删除两个 元素给出队列([7],[8]
队列(前端、后端)
。这个
如果两个列表都为空,则队列为空。如果将元素添加到
将它们添加到后端的队列;如果它们被移除,它们将被移除
从前端移除;如果前端变空(且
后端不为空)则后端将成为具有[]
作为新的后端。例如,我们可以从如下队列开始
队列([2,5,7],])
,添加8将为我们提供队列([2,5,7],[8])
,删除两个
元素给出队列([7],[8])
,添加9给出队列([7],[9,8])
,以及
删除一个元素会产生队列([9,8],])
我不明白我是如何创建并引用.pl
文件中的队列结构的,而其他谓词可以通过这种方式进行操作和转换
我大致勾勒出了我认为我应该做的事情,既定义了队列结构,也只是一个列表列表
将|添加到| q(X,[[H | T]|[H2 | T2],[[H | T]|[X |[H2 | T2]])。
队列(X,Y)
将_添加到_q(A,队列(X,Y),队列(X,[A | Y])。%给出语法错误:应为运算符
------------------
从_q([[H |[T | T3]][H2 | T2]],[[T | T3]][H2 | T2]]中移除_)。
队列(X,Y)
从_q(队列(X,[H | T])、队列(H,T)中移除_。
如何在Prolog中定义和使用结构,如何添加OO语言中的内容方法,例如getHead
或getTail
,我已经看到了一些示例,说明了如何仅使用列表来实现这一点,但我不是使用列表列表,而是使用两个单独列表的“队列”
感觉失落
我很难理解来自OO背景的语言
帮你自己一个忙,在学习Prolog的时候忘记你对OO的了解,这只会让你在学习Prolog的时候更加困惑。换句话说,不要想OO的概念,那么我该如何把它翻译成Prolog。思考一下如何构建越来越复杂的谓词
?-
empty(Q),
add(7,Q,Q2),
add(5,Q2,Q3),
add(2,Q3,Q4),
write(Q4),nl,
remove(Q4,A,Q5),
add(3,Q5,Q6),
remove(Q6,B,Q7),
remove(Q7,C,Q8),
remove(Q8,D,Q9),
empty(Q9),
write([A,B,C,D]).
我不明白我是如何在PL文件中创建并引用队列结构的,而其他谓词可以通过这种方式进行操作和转换 这些说明为您提供了数据结构的基础,即
queue(Front,Back)
前面和后面是一个列表。列表的示例
[]
[a]
[a,b]
[a|b]
引用队列很容易。由于Prolog使用语法统一,统一的一面是您想要统一的原子,例如,queue(Front,Back)
,而统一的另一面是queue(Front,Back)
的转换,您可以在编写的谓词中使用它们
你已经用电脑演示过了
add_to_q(A,queue(X,Y),queue(X,[A|Y])
请注意,它缺少一个结尾)
它缺少一个结尾
)
由于指令给出的示例非常有限,因此很难创建许多测试用例来确保代码在实际生产系统中工作 下面是基于这个问题的工作代码
add(Item,queue(Front,Back),queue(Front,[Item|Back])).
remove(Item,queue([Item|[]],Back),queue(Back,[])).
remove(Item,queue([Item|Front],Back),queue(Front,Back)).
:- begin_tests(funny_queue).
funny_queue_test_case_generator(add , 8 ,queue([2,5,7] ,[ ] ) ,queue([2,5,7],[8] ) ).
funny_queue_test_case_generator(remove, 2 ,queue([2,5,7] ,[ 8] ) ,queue([5,7] ,[8] ) ).
funny_queue_test_case_generator(remove, 5 ,queue([5,7] ,[ 8] ) ,queue([7] ,[8] ) ).
funny_queue_test_case_generator(add , 9 ,queue([7] ,[ 8] ) ,queue([7] ,[9,8] ) ).
funny_queue_test_case_generator(remove, 7 ,queue([7] ,[9,8] ) ,queue([9,8] ,[] ) ).
test(add,[forall(funny_queue_test_case_generator(add,Item,Funny_queue_0,Funny_queue))]) :-
add(Item,Funny_queue_0,Funny_queue_expected),
assertion( Funny_queue == Funny_queue_expected ).
test(add,[nondet,forall(funny_queue_test_case_generator(remove,Item,Funny_queue_0,Funny_queue))]) :-
remove(Item,Funny_queue_0,Funny_queue_expected),
assertion( Funny_queue == Funny_queue_expected ).
:- end_tests(funny_queue).
这是一个有趣的队列。当队列的后面移到前面时,项目以相反的顺序弹出。这不是真正的排队 不过,这些行动相当直接 首先,我们将把队列表示为复合术语
queue(X,Y)
,其中X
和Y
是表示队列前面和后面的列表
我们需要一种获取空队列的方法:
empty(queue([],[])).
要将项目添加到队列,请执行以下操作:
add(A,queue(X,Y),queue(X,[A|Y])).
remove(queue([A|T],X),A,queue(T,X)).
现在,说明不一致。他们说两个空列表代表一个空队列,新项目总是添加到后面的列表中。那么,如果第一个列表开始为空并且从未添加到中,它怎么可能变为空呢
因此,我们必须提供一个谓词,它允许我们从一个空的前列表中删除,只要后列表不是空的
remove(queue([],[A|X]),A,queue(X,[])).
这会将后面列表的尾部带到前面,并将尾部的第一个元素返回到A
最后,如果前面的列表不是空的,那么我们执行以下操作:
add(A,queue(X,Y),queue(X,[A|Y])).
remove(queue([A|T],X),A,queue(T,X)).
让我们测试这4个谓词
?-
empty(Q),
add(7,Q,Q2),
add(5,Q2,Q3),
add(2,Q3,Q4),
write(Q4),nl,
remove(Q4,A,Q5),
add(3,Q5,Q6),
remove(Q6,B,Q7),
remove(Q7,C,Q8),
remove(Q8,D,Q9),
empty(Q9),
write([A,B,C,D]).
Q9
在向队列添加4个原子并将其删除后必须为空<代码>[A、B、C、D]统一为[2,5,7,3]
Q4
是说明中描述的开始状态,尽管它是队列([],[2,5,7])
,因为我们被指示总是添加到后面的列表中
所以这一切都是按照我们被指示的方式进行的
但这不是真正的排队
如果这是一个真正的队列,那么添加的第一项应该是删除的第一项。预期输出为[7,5,2,3]
。为了实现这一点,我们将重写第一个remove
谓词,如下所示:
remove(queue([],Z),A,queue(X,[])) :- reverse(Z,[A|X]).
reverse(X,Y):- reverse(X,[],Y).
reverse([],A,A).
reverse([H|T],A,R) :- reverse(T,[H|A],R).
运行带有该更改的代码可以得到队列的预期输出。所说的。什么都忘了。这都是关于模式匹配的
这是您所需要的全部:
- 首先,创建空队列的方法:
- 一旦你做到了这一点,排队买东西就变得微不足道了。
这只是将已排队的项目预先添加到“后退”队列的问题:
说明:
prolog中的列表是递归数据结构。按照惯例,空列表是无效的
表示为原子
(将其视为字符串)。写入非空列表 使用方括号表示法([]
,[1]
等)。但是那只是句法上的 数据结构的糖[1,2]
:/2
是[1]
(1,[])
是[1,2]
(1,2,[])
- ……等等
enque( X , q(F,B) , q(F, [X|B] ) ) .
deque( q( [] , Bs ) , F , q( Fs , [] ) ) :- reverse( Bs, [F|Fs] ). deque( q( [F|Fs] , Bs ) , F , q( Fs , Bs ) ) .
empty( q([],[]) ). enque( X , q(F,B) , q(F, [X|B] ) ). deque( q( [] , Bs ) , F , q(Fs,[]) ) :- reverse( Bs, [F|Fs] ). deque( q( [F|Fs] , Bs ) , F , q(Fs,Bs) ). run_example :- empty( Q0 ) , writeln( queue : Q0 ) , enque( 1 , Q0 , Q1 ) , writeln( enque : Q1 ) , enque( 2 , Q1 , Q2 ) , writeln( enque : Q2 ) , enque( 3 , Q2 , Q3 ) , writeln( enque : Q3 ) , enque( 4 , Q3 , Q4 ) , writeln( enque : Q4 ) , deque( Q4 , X1 , Q5 ) , writeln( deque : x(X1) : Q5 ) , enque( 5 , Q5 , Q6 ) , writeln( enque : Q6 ) , enque( 6 , Q6 , Q7 ) , writeln( enque : Q7 ) , deque( Q7 , X2 , Q8 ) , writeln( deque : x(X2) : Q8 ) , deque( Q7 , X3 , Q9 ) , writeln( deque : x(X3) : Q9 ) , deque( Q9 , X4 , Q10 ) , writeln( deque : x(X4) : Q10 ) , deque( Q10 , X5 , Q11 ) , writeln( deque : x(X5) : Q11 ) , deque( Q11 , X6 , Q12 ) , writeln( deque : x(X6) : Q12 ) , deque( Q12 , X7 , Q13 ) , writeln( deque : x(X7) : Q13 ) , empty( Q13 ) .