[英]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.