无法将简单的python代码转换为haskell

时间:2016-11-20 15:40:30

标签: python haskell recursion

我正在尝试将其转换为Haskell,

def longest_path(edge, edges):
    remaining = list(edges)
    del remaining[remaining.index(edge)]
    possibles = [x for x in remaining if x[0] == edge[1]]
    maxchain = []
    for c in possibles:
        l = longest_path(c, remaining)
        if len(l) > len(maxchain):
            maxchain = l
    return [edge] + maxchain

据我所知,

deleteN :: Int -> [a] -> [a]
deleteN _ []     = []
deleteN i (x:xs)
   | i == 0    = xs
   | otherwise = x : deleteN (i-1) xs

longestPath edge edges = let
  remaining = deleteN (fromMaybe $ elemIndex edge edges) edges
  possibiles = [opt | opt <- remaining, (fst opt) == (snd edge)]

我无法弄清楚如何使用递归来执行for循环。有人有想法吗?

2 个答案:

答案 0 :(得分:4)

注意:这个答案写在有文化的Haskell中。将其保存为*.lhs并将其加载到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代码中做了什么?显然,我们从边缘列表中删除了当前的edge

    remaining = list(edges)
    del remaining[remaining.index(edge)]

幸运的是,有一个函数可以删除列表中元素的第一个出现位置,即delete

>     let remaining = delete edge edges

到目前为止一切顺利。现在,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

答案 1 :(得分:3)

那个python代码并不是最好的......我没有看到找到edge的索引,然后del找到它...只是使用edges.remove(edge)

在Haskell中以同样的方式,您只需filter边缘:

remaining = filter (/= edge) edges

现在,您的for循环正在跟踪目前为止的最佳结果。 Haskell中的这个可以通过使用累加器参数的递归函数来完成。但是,此处的模式是fold

的模式
foldr f [] possibilities

其中:

f c maxchain = let l = longestPath c remaining
               in
                   if length l > length maxchain then l else maxchain

您可以修改longestPath以返回路径的长度,并避免调用length ...

完整的代码如下:

longestPath edge edges = foldr f [] possibilities
  where
    remaining = filter (/= edge) edges
    possibilities = [opt | opt <- remaining, (fst opt) == (snd edge)]
    f c maxchain = if length l > length maxchain then l else maxchain
      where
        l = longestPath c remaining

正如评论中指出的那样,filter代替delete edge edges,您可以使用edge删除一个出现的<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="CalimplService" targetNamespace="http://webservice.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://webservice.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="com.webservice" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"> <wsdl:import namespace="com.webservice" location="Ical.wsdl"> </wsdl:import> <wsdl:binding name="CalimplServiceSoapBinding" type="ns1:Ical"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="rech"> <soap:operation soapAction="urn:Rech" style="document"/> <wsdl:input name="rech"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="rechResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="CalimplService"> <wsdl:port name="CalimplPort" binding="tns:CalimplServiceSoapBinding"> <soap:address location="http://localhost:8080/Calcu/services/CalimplPort"/> </wsdl:port> </wsdl:service> </wsdl:definitions> 。但是,如果你正在处理标准图表,这不重要。