[英]Prolog create list of lists
我在prolog中遇到列表列表时遇到了一些(或很多)问题。
所以我有一个数字列表,比如[5,6,1,3]作为输入。 输出应为[[5,25],[6,36],[1,1],[3,9]]。
我已经有一个谓词'返回2个项目列表(请记住,我必须更改get_squared_pair函数以获得一些其他相关值):
get_squared_pair(Number, Result) :-
get_squared_value(Number, SquareValue),
Result = [Number, SquareValue].
get_squared_value(Number, Result) :-
Result is Number * Number.
直到这里它是非常合乎逻辑的。 现在我需要一个谓词递归迭代列表,将平方对添加到新列表,然后返回列表列表。 我现在拥有的是:
return_list([], 0).
return_list([Head | Tail], Result) :-
get_squared_pair(Head, Add),
append(Add,Result),
return_list(Tail, Result).
这不是出于多种原因,而且主要是因为我似乎无法弄清楚递归实际上如何与列表一起工作,更不用说列表列表了。 此外,它目前以错误的顺序运行,但没有帮助。
我知道这可能有点模糊,但我已经尝试用谷歌搜索出来了,但似乎无法将我发现的内容很好地转化为我自己的问题。
任何帮助将非常感激!
我们先来看看你的get_squared_pair/2
。 虽然它有效,但它可以整理一下,这也有助于理解Prolog的工作原理。 Prolog的主要机制是统一 ,这与其他语言中的赋值不同。 在统一中 ,Prolog检查两个术语并尝试通过在一个或两个术语中实例化变量来使它们匹配来统一它们。 Prolog中有一些谓词,比如is/2
,用于在一个参数中计算表达式,然后用该结果统一第一个参数。
那么你的第一个谓词就是:
get_squared_pair(Number, Result) :-
get_squared_value(Number, SquareValue),
Result = [Number, SquareValue].
get_squared_value(Number, Result) :-
Result is Number * Number.
可以通过两种方式简化。 首先,你可以合并get_squared_value/2
因为它只是一行,并不真正需要它自己的谓词。 我们将重命名谓词,因此它不是必须的。
square_pair(Number, Square) :-
S is Number * Number, % Square the number
Square = [Number, S]. % Unify Square with the pair
Prolog可以统一条款开头的条款,这样就可以避免多余的统一。 所以这就是你所需要的:
square_pair(Number, [Number, Square]) :-
Square is Number * Number.
在主谓词上, return_list/2
。 首先,我们将这个谓词重命名为square_pairs
。 使用列表进行递归时,最常见的模式是继续减少列表,直到它为空,然后基本案例处理空列表。 您的实现会这样做,但基本情况有点困惑,因为第二个参数是整数而不是列表:
square_pairs([], 0).
这应该是:
square_pairs([], []).
你的主谓词条款没有正确使用append/2
。 在SWI Prolog中有两种形式的append
: append/2
和append/3
。 您可以在SWI Prolog在线文档中查找这些内容。 我可以告诉你,在Prolog中, 除了通过回溯之外 , 你不能在谓词子句实例化之后更改变量的值 。 例如,查看谓词子句中可能包含的以下序列:
X = a, % Unify X with the atom 'a'
X = b, % Unify X with the atom 'b'
在这种情况下,第二个表达式将始终失败,因为X
已经统一并且无法再次统一。 但是,如果我有这个:
foo(X), % Call foo, which unifies X with a value that makes 'foo' succeed
bar(X, Y), % Call bar, which might fail based upon the value of 'X'
在上面的例子中,如果bar(X, Y)
失败,那么Prolog将回溯到foo(X)
调用并寻找另一个X
值,这使得foo(X)
成功。 如果找到一个,那么它将再次使用新值X
调用bar(X, Y)
,依此类推。
所以append(Add, Result)
不追加Add
到Result
产生了一个新的价值Result
。 事实上, append
两个参数说第二个列表参数是第一个列表的所有元素的串联,假设第一个参数是列表列表,所以append/2
的定义无论如何都不匹配。
在考虑你的递归时,要意识到参数列表是彼此一一对应的。 结果列表的头部是第一个参数中列表头部的“方形对”。 然后,递归地,第二个参数的尾部是第一个参数的尾部的平方对的列表。 你只需要在Prolog中表达它。 我们也可以使用上面描述的技术在条款的头部进行统一。
square_pairs([Head | Tail], [SqPair | SqTail]) :-
square_pair(Head, SqPair),
square_pairs(Tail, SqTail).
square_pairs([], []).
现在我们可以做另一个简化,它完全消除了square_pair/2
辅助谓词:
square_pairs([Head | Tail], [[Head, SqHead] | SqTail]) :-
SqHead is Head * Head,
square_pairs(Tail, SqTail).
square_pairs([], []).
在Prolog中有一个方便的谓词maplist
,它可以用来定义一个在两个列表之间并行运行的关系,这就是我们这里的场景。 我们可以带回square_pair/2
谓词和使用maplist
:
square_pairs(Numbers, SquarePairs) :-
maplist(square_pair, Numbers, SquarePairs).
所以你想把你的列表变成另一个,这样每个元素(一个数字)就变成了一个双元素列表,数字和它的正方形。
您需要做的就是告诉Prolog。 一,第二个:
turn_into_two(Num, [A,B]):-
什么是A
?
A is Num,
什么是B
? 我们也告诉Prolog:
B is ... * ... .
现在,到我们的列表。 Prolog中的列表[A|B]
由其头部元素A
和尾部B
- 除非它当然是空列表[]
。 列表的元素是什么并不重要; 列表是一个列表。
我们需要考虑所有情况,否则我们不是在谈论列表而是其他事情:
turn_list([], Res):-
那么如果列表为空,我们的结果是什么? 它也应该是空的,对吧?
Res = ... .
在另一种情况下,
turn_list([A|B], Res):-
我们的结果不会是空的,所以它的头部和尾部都是正确的,对吗?
Res = [C|D],
接下来我们说出我们对头部的了解:输入列表的头部变成我们上面描述的两个元素列表,对吗?
turn_into_two(A,C),
然后我们说我们关于尾巴的文章。 但是我们对尾巴了解多少? 我们知道一个是另一个转换的结果,就像整个列表一样:
turn_list( ... , ...) .
就是这样。 顺便提一下,我们所描述的,遵循映射的范例。 我们可以使用任何其他谓词代替turn_into_two/2
,并且将为输入列表的每个元素以及结果列表中的对应元素调用它 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.