如何计算函数的总和?

pvl*_*pvl 2 haskell

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

A 1.0 2.2
B 2.1 3.0
C 3.5 4.0
D 4.0 5.0
Run Code Online (Sandbox Code Playgroud)

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

route1 ACDB
route2 ABC
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

如何计算路线的全程?

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

提前致谢.

And*_*ewC 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
Run Code Online (Sandbox Code Playgroud)

然后有一些练习数据:

sampleData :: Points
sampleData = [('A',(1.0,2.2), .....
Run Code Online (Sandbox Code Playgroud)

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

首先,你需要一个带名字的函数并给你一些坐标.

coordinates :: Points -> Name -> Coordinates
Run Code Online (Sandbox Code Playgroud)

如果我们正在使用[Point],最简单的方法是使用lookup.(你可以找到关于hoogle功能这样或类型这样的,虽然有让你知道你想要一个没有明显的方式Maybe,当你只是搜索[(a,b)] -> b,查找是一个很长的路了.)

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

使用它你就可以写

distBetween :: Points -> Name -> Name -> Float
Run Code Online (Sandbox Code Playgroud)

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

getPath :: String -> [(Name,Name)]
Run Code Online (Sandbox Code Playgroud)

或(冷却器)zipWith用来到达距离.之后,申请sum应该很容易完成问题.

制作这个对列表的很酷的方法是使用我们用于fibs = 0 : 1 : zipWith (+) fibs (tail fibs)使用其尾部压缩函数的fibonacci数字()的技巧.如果你没有遇到它,zip就像这样:

 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')]
Run Code Online (Sandbox Code Playgroud)

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

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

你需要像这样的功能

readPointsFile :: FilePath -> IO Points
readPointsFile fileName = do
    ....
    ....
    return (map readPoint pointStrings)
Run Code Online (Sandbox Code Playgroud)

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

pathLengthFile :: FilePath -> FilePath -> IO Float
pathLengthFile pointsFilename pathFilename = do
     points <- readPointsFile pointsFilename
     path <- readPathFile pathFilename
     return (getPathLength points path)
Run Code Online (Sandbox Code Playgroud)

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


偷偷地说,我是一个巨大的Applicative粉丝,并希望import Control.Applicative并将其写成

pathLengthFile pointsFile pathFile = 
    getPathLength <$> readPointsFile pointsFile <*> readPathFile pathFile
Run Code Online (Sandbox Code Playgroud)

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