List 惯用表结构
一般来说,我对Haskell和函数式编程非常陌生,所以我真的不知道如何使这段代码习惯化:List 惯用表结构,list,haskell,functional-programming,idioms,List,Haskell,Functional Programming,Idioms,一般来说,我对Haskell和函数式编程非常陌生,所以我真的不知道如何使这段代码习惯化: type Coord = Double data Point = Point Coord Coord Coord deriving Show type Polyline = [Point] -- Add a point to a polyline addPoint :: Polyline -> Point -> Polyline addPoint line p = p:line line
type Coord = Double
data Point = Point Coord Coord Coord deriving Show
type Polyline = [Point]
-- Add a point to a polyline
addPoint :: Polyline -> Point -> Polyline
addPoint line p = p:line
line :: Polyline
line = []
constructLine :: Polyline -> Polyline
constructLine line =
let
p1 = Point 2 4 87
p2 = Point 3 7 2
p3 = Point 23 4 8
in addPoint (addPoint (addPoint line p1) p2) p3
main :: IO()
main = do
putStrLn ( show (constructLine line))
我的问题是
constructLine
函数。如果我想添加很多点,嵌套的addPoint
函数将是一个问题。我怎样才能考虑到这一点?还有其他可以改进的地方吗?对addPoints的多次调用可以用一次折叠来代替。正如一条评论中所建议的,反转addPoint函数将使事情变得更简单:
addPoint' :: Point -> Polyline -> Polyline
addPoint' p line = p:line
这样,您的constructLine函数就可以构建一个临时的点列表来添加使用折叠:
constructLine :: Polyline -> Polyline
constructLine line =
let
p1 = Point 2 4 87
p2 = Point 3 7 2
p3 = Point 23 4 8
in foldr addPoint' line [p3,p2,p1]
这不会破坏封装(您可以用点列表以外的其他内容替换多段线的实现),并按照新点的结束顺序(p2前面的p3等)使用新点。对addPoints的多次调用可以用折叠来代替。正如一条评论中所建议的,反转addPoint函数将使事情变得更简单:
addPoint' :: Point -> Polyline -> Polyline
addPoint' p line = p:line
这样,您的constructLine函数就可以构建一个临时的点列表来添加使用折叠:
constructLine :: Polyline -> Polyline
constructLine line =
let
p1 = Point 2 4 87
p2 = Point 3 7 2
p3 = Point 23 4 8
in foldr addPoint' line [p3,p2,p1]
这不会破坏封装(您可以用点列表以外的其他内容替换多段线的实现),并按照新点的结束顺序(p2前面的p3等)使用新点。您的
构造线
示例让我觉得这是一个冗长的版本:
constructLine :: Polyline -> Polyline
constructLine line = [Point 23 4 8, Point 3 7 2, Point 2 4 87] ++ line
type Coord = Double
data Point = Point Coord Coord Coord deriving Show
main :: IO ()
main = putStrLn (show points)
where points = [Point 23 4 8, Point 3 7 2, Point 2 4 87]
我不知道您是否遇到过这些问题,但可以肯定的是:
只是一个列表文字[第23 4 8点、第3 7 2点、第2 4 87点]
是附加列表的函数++
行
是一个定义为[]
的常数,那么您的整个程序实际上只是一个冗长的版本:
constructLine :: Polyline -> Polyline
constructLine line = [Point 23 4 8, Point 3 7 2, Point 2 4 87] ++ line
type Coord = Double
data Point = Point Coord Coord Coord deriving Show
main :: IO ()
main = putStrLn (show points)
where points = [Point 23 4 8, Point 3 7 2, Point 2 4 87]
基本上,如果点的值在编译时已知,您只需编写列表,无需进行所有这些间接操作 您的
constructLine
示例对我来说是一个冗长的版本:
constructLine :: Polyline -> Polyline
constructLine line = [Point 23 4 8, Point 3 7 2, Point 2 4 87] ++ line
type Coord = Double
data Point = Point Coord Coord Coord deriving Show
main :: IO ()
main = putStrLn (show points)
where points = [Point 23 4 8, Point 3 7 2, Point 2 4 87]
我不知道您是否遇到过这些问题,但可以肯定的是:
只是一个列表文字[第23 4 8点、第3 7 2点、第2 4 87点]
是附加列表的函数++
行
是一个定义为[]
的常数,那么您的整个程序实际上只是一个冗长的版本:
constructLine :: Polyline -> Polyline
constructLine line = [Point 23 4 8, Point 3 7 2, Point 2 4 87] ++ line
type Coord = Double
data Point = Point Coord Coord Coord deriving Show
main :: IO ()
main = putStrLn (show points)
where points = [Point 23 4 8, Point 3 7 2, Point 2 4 87]
基本上,如果点的值在编译时已知,您只需编写列表,无需进行所有这些间接操作 提供一个函数,该函数在给定点列表的情况下构造多段线。例如,您可以执行添加点行ps=ps++line或类似操作。顺便说一句:你也可以用中缀符号调用
addPoint
。惯用的方法可能是放弃addPoint
,直接将列表构建为[p3,p2,p1]
,但是如果你想保留这个抽象,那么只需创建你自己的操作符,比如infixr 5
,(\code>)::Point->Polyline->Polyline
,(#)=addPoint
(注意,我在这里交换了参数顺序)。infixr
行很重要,请确保您保留它,但这意味着您可以将其写成p3#p2#p1#行
。如果您真的想保持参数顺序,请执行infixl 5#
,它将被写为line#p1#p2#p3
。请注意,如果您更改参数顺序,使其成为addPoint::Point->Polyline->Polyline
,则可以将其写为addPoint p3$addPoint p2$addPoint p1 line
,这对于您的目的可能已经足够了。请提供一个函数,该函数给定一个点列表来构造一条多段线。例如,您可以执行添加点行ps=ps++line或类似操作。顺便说一句:你也可以用中缀符号调用addPoint
。惯用的方法可能是放弃addPoint
,直接将列表构建为[p3,p2,p1]
,但是如果你想保留这个抽象,那么只需创建你自己的操作符,比如infixr 5
,(\code>)::Point->Polyline->Polyline
,(#)=addPoint
(注意,我在这里交换了参数顺序)。infixr
行很重要,请确保您保留它,但这意味着您可以将其写成p3#p2#p1#行
。如果您真的想保持参数顺序,请执行infixl 5#
,它将被写为line#p1#p2#p3
。请注意,如果您更改参数顺序,使其成为addPoint::Point->Polyline->Polyline
,则可以将其写为addPoint p3$addPoint p2$addPoint p1 line
,这对你的目的可能足够了。是的,我知道这一点,但我想抽象多段线结构。无论如何,谢谢你的回答@ElieGnrd:如果多段线在概念上类似于列表,但有一些不变量需要保护,一种简单的方法是在不透明的多段线
类型和点列表之间来回转换函数。然后,可以通过列表操作(Haskell非常支持)完成很多逻辑,要创建多段线,只需提供一个列表即可。例如,Haskell平台中的Data.Map.Map
类型的工作原理如下:创建一个映射的最常见方法之一是使用函数fromList::Ord k=>[(k,v)]->Map k