[英]Return a list of even numbers from a list of integer pairs in sml
我有以下問題“給定一個 integer 對的列表,寫一個 function 以在 sml 中返回該列表中的偶數列表”。
這是我到目前為止所取得的成就
val x = [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
fun isEven(num : int) =
if num mod 2 = 0 then num else 0;
fun evenNumbers(list : (int * int) list) =
if null list then [] else
if isEven(#1 (hd list)) <> 0
then if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
else []
else if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: evenNumbers(tl list)
else [];
evenNumbers(x);
結果應該是這樣的[6,2,4,6,8,10]
任何幫助,將不勝感激。
我看到兩個明顯的問題。
如果第一個和第二個數字都是偶數,你做
#1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
它將第一個數字添加兩次並忽略第二個。
如果第一個數字是奇數,第二個數字是偶數,你做
#1 (hd list) :: evenNumbers(tl list)
它將您知道的奇數相加,而忽略您知道的偶數。
使用選擇器和條件進行編程會很快變得復雜(正如您所注意到的)。
使用模式匹配,您可以編寫
fun evenNumbers [] = []
| evenNumber ((x,y)::xys) = ...
並降低使用錯誤選擇器的風險。
但是,這仍然會導致復雜的邏輯,並且有更好的方法。
考慮從數字列表而不是對中過濾奇數的更簡單問題。
如果您將輸入轉換為這樣的列表,您只需要解決那個更簡單的問題(並且很有可能您已經在之前的練習中解決了非常相似的問題)。
練習:實現這個轉換。 它的類型將是('a * 'a) list -> 'a list
。
此外,如果您的isEven
產生真值(如果您問某人,“36 是偶數嗎?”,“36”是一個非常奇怪的答案),它會更有用。
fun isEven x = x mod 2 = 0
現在, evenNumbers
可以實現為“只是”其他更通用函數的組合。
所以運行你當前的代碼,
- evenNumbers [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
val it = [6,6,3,5,7,9] : int list
表明您沒有捕獲所有偶數,並且您正在捕獲一些奇數。
function isEven
聽起來很像您想要int -> bool
類型,如下所示:
fun isEven n =
n mod 2 = 0
我不想解決當前解決方案的邏輯錯誤,而是提出一種語法上更簡單的方法,即使用模式匹配和更少的顯式類型注釋。 這種解決方案的一個基礎可能如下所示:
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) = ...
使用模式匹配是 if-then-else 的替代方法: []
模式等效於if null list...
並且(x,y)::pairs
模式在輸入列表非空時匹配(至少包含一個元素,即(x,y)
。同時,它將這個元素解構為它的部分x
和y
。所以在第二個 function 主體中,您可以表示isEven x
和isEven y
。
由於x
和y
是否偶數總共有四種組合,因此很容易以類似復雜的 if-then-else 嵌套結束。 為此,我可能會做以下兩件事之一:
使用 case-of(並在pairs
上遞歸調用evenNumbers
):
fun evenNumbers [] =... | evenNumbers ((x,y)::pairs) = case (isEven x, isEven y) of... =>... |... =>...
將對列表展平為整數列表並filter
它:
fun flatten [] =... | flatten ((x,y)::pairs) =... val evenNumbers pairs =...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.