如何计算函数的总和?

时间:2013-06-09 22:02:42

标签: haskell

我有一个文件(points.txt),其中定义了一些笛卡尔坐标:

A 1.0 2.2
B 2.1 3.0
C 3.5 4.0
D 4.0 5.0

我有第二个文件(routes.txt),其路线是根据points.txt中的点定义的。

route1 ACDB
route2 ABC

我需要找到每条路线的长度。到目前为止,我计算了两点之间的距离,如下所示:

type Point = (String, Float, Float)

distance_points :: IO ()
distance_points = do s <- readFile "pontos.txt"
                      putStr "Fom: "
                      p1 <- getLine
                      putStr "To: "
                      p2 <- getLine
                      print ( distance (search_point p1 (map words (lines s))) (search_point p2 (map words (lines s))))

search_point :: String -> [[String]] -> Point
search_point pt ([p,c1,c2]:xs) = if pt == p then (p, read(c1)::Float, read(c2)::Float)
                                             else search_point pt xs

distance :: Point -> Point -> Float
distance (s1,x1,y1) (s2,x2,y2) = sqrt ((x1-x2)^2 + (y1-y2)^2)

如何计算路线的全程?

另外,如果我有几条路线,我怎样才能找到最长的路线?

提前致谢。

1 个答案:

答案 0 :(得分:8)

步骤1:通过不写IO直到结束来分离纯代码和非纯代码。

最简单的方法是先用纯代码解决问题,然后再添加文件读取。否则你会想要编写很多IO代码。

如果将名称与坐标分开,将会更容易:

type Coordinates = (Float,Float)
type Name = Char -- You had String, which is also fine
type Point = (Name, Coordinates)
type Points = [Point] -- or Map String Point from Data.Map

然后有一些练习数据:

sampleData :: Points
sampleData = [('A',(1.0,2.2), .....

第2步:编写一个函数,该函数采用点和一对点名称的集合并返回距离

首先,你需要一个带名字的函数,并为你提供一些坐标。

coordinates :: Points -> Name -> Coordinates

如果我们使用[Point],最简单的方法是使用lookup。 (你可以在hoogle like this或类型like this上找到相关功能,但是没有明显的方法让你知道你想要Maybe,当你只是搜索{{ 1}},查找还有很长的路要走。)

如果您需要有关此步骤的帮助,请发表评论。

使用它你就可以写

[(a,b)] -> b

步骤3:将表示路径的名称列表转换为点名称对

列表
distBetween :: Points -> Name -> Name -> Float

或(冷静)使用getPath :: String -> [(Name,Name)] 来达到距离。之后,应用zipWith应该很容易解决问题。

制作这个对列表的一个很酷的方法是使用我们用于使用其尾部压缩函数的斐波纳契数(sum)的技巧。如果您没有遇到它,zip的工作原理如下:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

太棒了 - 这正是你需要的技巧。

步骤4:最后,将代码读取文件写入您需要的数据类型

你需要像

这样的功能
 ghci> zip [1..5] "Hello Mum"
[(1,'H'),(2,'e'),(3,'l'),(4,'l'),(5,'o')]
zip "Hello" "ello"
[('H','e'),('e','l'),('l','l'),('l','o')]
*Main> zip "Hello" (tail "Hello")
[('H','e'),('e','l'),('l','l'),('l','o')]

然后你可以将它粘在一起,例如:

readPointsFile :: FilePath -> IO Points
readPointsFile fileName = do
    ....
    ....
    return (map readPoint pointStrings)

注意这个位中几乎没有任何逻辑。你可以用纯粹的代码完成所有真正的移植。


暗地里我是一个庞大的pathLengthFile :: FilePath -> FilePath -> IO Float pathLengthFile pointsFilename pathFilename = do points <- readPointsFile pointsFilename path <- readPathFile pathFilename return (getPathLength points path) 粉丝,想要Applicative并将其写成

import Control.Applicative

但这是后来的另一个教训。 :)