我正在学习Haskell并遇到一个问题,我正在尝试迭代列表,但我需要能够返回到列表的开头。例如,如果我的元组列表是:
[(1,5), (4,3), (5,6), (1,7), (7,9), (3,11)]
我需要从1到4到5 ...我正在通过递归调用列表尾部的函数来执行此操作。这应该工作,但这是问题:
我将这些数字与另一个元组列表进行匹配。例如,我的第二个列表就像是
[(6,10)]
所以1或5都不匹配6或10,4或3都不匹配6或10但(5,6)
匹配6,所以我会将它添加到前面。现在我需要从列表的前面开始。问题是我迭代的方式,通过调用尾调用函数意味着我无法看到(1,5), (4,3)
我一直在努力从概念上解决这个问题半个星期。我知道整个(head list) : function (tail list)
如何,但是因为我的回归是匹配对的新列表,所以我无法完成这项工作。
不确定这是否有意义,但简而言之,在将(5,6)
添加到列表后,我得到[(5,6),(6,10)]
的结果,这很好,但是当我想现在再次开始检查时,它以{开头{1}}代替现在匹配的(1,7)
。
我的代码现在处于解决方案的中间,因此显示它将是一个巨大的混乱。另外,我真的只是想帮助试图概念化我必须做的事情。
修改
好了清除一些混淆,让我说我有两个清单:
(1,5)
我有一个函数,它接受两个列表并返回更新的list2。 List1将它的元组中的字符与list2的元组前后的字符进行比较(我不想在它们之间插入链接list1: [(8,7),(1,5),(8,9),(4,3),(5,6),(1,7),(11,9)]
list2: [(6,10),(10,12)]
)。首先,...,10)<-->(10,...
与(8,7)
或6
不匹配,所以我继续前进。现在当我继续前进时,我正在回调我的函数并将它传递给list1的尾部。
例如:
12
我没有写出所有的比较来节省空间,但它们都工作得很好,除了一部分外,它应该通过列表。回到列表,我现在有master list1 list2
| comparisons.... = master (tail list1) (addToList list2)
.
.
.
| otherwise = master (tail list1) list2
哪个反对不匹配所以我把尾巴传递到(1,5)
,再没有任何东西让我进步,(8,9)
不匹配所以我到达匹配的(4,3)
,我可以将其翻转并将其添加到前面以生成(5,6)
,现在我将从list1中删除[(5,6),(6,10),(10,12)]
,因为我已将其添加到list2。问题是现在我将再次传递尾部并且在(5,6)
然后(1,7)
然后结束程序,因为我们在列表的末尾。
我想要的输出是(11,9)
而不是[(11,9),(9,8),(8,7),(7,1),(1,5),(5,6),(6,10),(10,12)]
同样,代码并没有真正帮助我,我只是希望有人提供一种不同的方式来思考它。这是我第一次接触一种功能性语言,并说我对部件感到困惑是一种轻描淡写。
答案 0 :(得分:1)
既然你正在学习Haskell,我想你可能想自己解决这个问题,所以让我告诉你如何解决一个更简单的变化。假设我们有一个单词列表,我们想要建立一个新的单词列表,其中对于每个相邻的对,该对中第一个单词的最后一个字母与最后一个单词的第一个字母匹配。但是,我们只会 在我们列表的末尾添加单词(与您可以在开头或结尾添加对的示例不同,或者甚至可能在中间的某个位置添加单词 - 它不是&# 39;从你的描述中清楚)。
所以,如果我们从一个单词列表开始:
["cat","bat","cow","war","rot","tar"]
和#34;种子&#34;列表:
["tub"]
然后我们就像:
link ["cat","bat","cow","war","rot","tar"] ["tub"]
给予:
["tub","bat","tar","rot"]
此处,从列表["tub"]
开始,我们找到了启动的第一个单词&#34; b&#34;,因此我们可以将其添加到得到["tub","bat"]
的结尾,然后我们搜索以&#34; t&#34;开头的剩余第一个单词。得到["tub","bat","tar"]
,然后我们搜索以&#34; r&#34;开头的第一个剩余单词获得["tub","bat","tar","rot"]
,然后程序结束,因为没有剩余的单词以&#34; t&#34;开头。
我们的第一次尝试(我认为与上面的算法类似)可能是:
link :: [String] -> [String] -> [String]
link (wrd:wrds) chain
| lastLetter == head wrd = link wrds (chain ++ [wrd])
| otherwise = link wrds chain
where lastLetter = last (last chain)
link [] chain = chain
不幸的是,这给出了错误的答案:
> link ["cat","bat","cow","war","rot","tar"] ["tub"]
["tub","bat","tar"]
>
它错过"rot"
,因为它只会在添加"tar"
后处理单词列表的尾部,并且不再有单词。你需要它回到列表的开头,这就是你被困住的地方。
问题在于,当您在"bat"
上获得第一次成功匹配时,递归调用是:
link wrds (chain ++ [wrd])
=
link ["cow","war","rot","tar"] (["tub"] ++ ["bat"])
而不是:
link wrds (chain ++ [wrd])
=
link ["cat","cow","war","rot","tar"] (["tub"] ++ ["bat"])
您需要包含已经处理过的不匹配字词列表(即["cat"]
)以及字词列表的尾部(以"cow"
开头)。
在Haskell中,如果您需要一些信息(例如&#34;您已经处理过的无法匹配的单词列表),您通常会将其作为额外参数传递。所以,让我们重写link
来获取额外的列表:
link' :: [String] -> [String] -> [String] -> [String]
link' unmatched (wrd:wrds) chain = ...
认为不匹配单词的初始列表将为空:
> link' [] ["cat","bat","cow","war","rot","tar"] ["tub"]
现在,让我们弄清楚link'
的定义。我们将从最简单的案例开始,&#34;否则&#34; case,我们在当前wrd
上进行了 not 匹配。在这种情况下,我们会将wrd
添加到不匹配字词列表中,然后继续查看其余wrds
:
... | otherwise = link' (unmatched ++ [wrd]) wrds chain
另一方面,如果我们做匹配,我们想要将这个词添加到链中:
... | lastLetter == head wrd = link' ?? ?? (chain ++ [wrd])
但前两个论点应该是什么?好吧,我们想要重新开始,查看列表中除我们匹配的wrd
之外的所有单词。也就是说,我们希望查看所有unmatched
个字词以及wrds
的其余部分,以便我们想要:
... | lastLetter == head wrd = link' ?? (unmatched ++ wrds) (chain ++ [wrd])
此次通话的第一个参数怎么样?好吧,我们重新开始,所以没有任何不匹配的单词 - 不匹配的列表应该是空的:
... | lastLetter == head wrd = link' [] (unmatched ++ wrds) (chain ++ [wrd])
这提供了完整,更新的定义:
link' :: [String] -> [String] -> [String] -> [String]
link' unmatched (wrd:wrds) chain
| lastLetter == head wrd = link' [] (unmatched ++ wrds) (chain ++ [wrd])
| otherwise = link' (unmatched ++ [wrd]) wrds chain
where lastLetter = last (last chain)
终止案例如何:
link' unmatched [] chain = ???
这可能有点棘手。但是,请记住,如果我们匹配一个单词,我们会跳回到开头:
link' [] (unmatched ++ wrds) (chain ++ [wrd])
如果还剩下至少一个单词(即如果(unmatched ++ wrds)
非空),我们将继续使用非终止案例。我们可以达到终止案例的唯一方法是if(1)我们匹配最后一个可用的单词并跳回到&#34;开始&#34;使用空单词列表,或者(2)我们在没有匹配的情况下到达单词列表的末尾。在 的情况下,链完成 - 在情况(1)中,单词列表中的所有单词都已成功添加到链中;在情况(2)中,单词列表是非空的,但是没有一个单词可以成功添加。因此,在 的情况下,我们想要停止并返回链,终止案例是:
link' unmatched [] chain = chain
当你使用&#34;额外&#34;像这样的参数,在辅助函数中包含它是很常见的,所以link
的最终修订定义看起来像这样:
link :: [String] -> [String] -> [String]
link wrds chain = link' [] wrds chain
where
link' unmatched (wrd:wrds) chain
| lastLetter == head wrd = link' [] (unmatched ++ wrds) (chain ++ [wrd])
| otherwise = link' (unmatched ++ [wrd]) wrds chain
where lastLetter = last (last chain)
link' unmatched [] chain = chain
现在给出了正确答案:
> link ["cat","bat","cow","war","rot","tar"] ["tub"]
["tub","bat","tar","rot"]
>