注意:这个答案写在文学Haskell。将其保存为3210并将其加载到GHCi中。
> import Data.Ord (comparing)
> import Data.List (delete, maximumBy)
> type Edge = (Int, Int)
让我们来看看你的Python代码,并认为Haskell的功能应该如何看起来像:
def longest_path(edge, edges):
还好吧。我们从一个边和一个边的列表开始。因此,我们应该编写一个这样的函数:
> longestPath :: Edge -> [Edge] -> [Edge]
> longestPath edge edges =
现在,我们在我们的Python代码中做什么?
remaining = list(edges)
del remaining[remaining.index(edge)]
幸运的是,删除元素第一次出现在列表中,即delete
功能:
> let remaining = delete edge edges
所以很显然,我们从边缘的列表中删除我们目前edge
非常好。现在,possibles
只是用正确的终点边缘的名单:
possibles = [x for x in remaining if x[0] == edge[1]]
那是太容易了:
> possibles = filter (edge `connectedTo`) edges
然后我们寻找所有可能的边缘链最长。
maxchain = []
for c in possibles:
l = longest_path(c, remaining)
if len(l) > len(maxchain):
maxchain = l
既然我们不能在Haskell修改maxchain
,让我们创建所有的中间路径来代替:
> paths = [] : map (\e -> longestPath e remaining) possibles
这就是递归发生。对于我们可能的边缘中的每个Edge
,我们创建该边缘的longestPath
和其余边缘。
for
环的大部分可以表示为map
和以下的折叠。我们将使用折叠是maximumBy
,在这里我们通过它们的长度与comparing length
比较列表:虽然
> in edge : maximumBy (comparing length) paths
我们已经使用了一个小帮手,connectedTo
。但是,这很简单:
> connectedTo :: Edge -> Edge -> Bool
> connectedTo (_,b) (x,_) = b == x
所有代码一次:
import Data.List (delete, maximumBy)
import Data.Ord (comparing)
type Edge = (Int, Int)
longestPath :: Edge -> [Edge] -> [Edge]
longestPath edge edges =
let remaining = delete edge edges
possibles = filter (edge `connectedTo`) edges
paths = [] : map (\e -> longestPath e remaining) possibles
in edge : maximumBy (comparing length) paths
connectedTo :: Edge -> Edge -> Bool
connectedTo (_,b) (x,_) = b == x
你不需要外在的循环或递归。 “为列表中的每个元素计算一些东西”,这里有一个名为'map'的内置函数。“查看列表并根据前一个值和当前列表元素更新一个值”另一个内置的foldr。 –
@nm这个'for'不是'map',因为它在循环中跟踪最好的'maxchain' ......它更像是一个'fold'。 – Bakuriu