data Point = Point Float Float deriving (Show)
data Line = Line Point Point deriving (Show)
onLine :: Line -> Point -> Bool
onLine (Line (Point x1 y1) (Point x2 y2)) (Point x y) = True
有没有办法不使用这么多括号?
data Point = Point Float Float deriving (Show)
data Line = Line Point Point deriving (Show)
onLine :: Line -> Point -> Bool
onLine (Line (Point x1 y1) (Point x2 y2)) (Point x y) = True
有没有办法不使用这么多括号?
我推荐一个名为hlint的工具来识别可以简化代码的地方。
在您的代码/所写的/中,您没有使用值、、、、x1
或,y1
因此您可以只写:x2
y2
x
y
onLine _ _ = True
但是,我认为这只是一个存根,实际上您将对变量做一些事情。一般来说,如果您真的需要引用所有这些变量,那么您需要按照您的方式编写它。但是,也许您正在使用只需要整个行值的辅助函数。然后你可以写这样的东西:
onLine l p = blah blah blah
-- use slope l and yIntercept l to figure out if p is on the line
slope :: Line -> Float
slope (Line (Point x1 y1) (Point x2 y2)) = (y2 - y1) / (x2 - x1)
yIntercept :: Line -> Float
yIntercept (Line (Point x1 y1) (Point x2 y2)) = blah blah blah
或者,您可以只使用访问器函数从点和线中提取 x 和 y 坐标,但在这种情况下,它可能会使您的代码更加混乱。
此外,在 Haskell 中,我相信使用它通常Double
比使用Float
.
有时您可以避免使用记录符号、有时使用$
、有时使用中缀函数的括号,有时如果不过分也可以。
让我们对点使用记录符号,这对坐标的访问量很大,但我们将不理会Line
。
data Point = Point {x::Double,y::Double} deriving (Show)
data Line = Line Point Point deriving (Show)
这定义了x :: Point -> Double
和y :: Point -> Double
。
浮点数没有相等之类的东西,但我会大致正确:
accuracy = 0.000000000001
is :: Double -> Double -> Bool
is x y = abs (x - y) < accuracy
我可以使用它来x point1 `is` x point2
巧妙地避免括号is (x point1) (x point2)
当您的数据结构没有与模式匹配如此紧密地嵌套时,一些括号很容易阅读:
gradient :: Line -> Double
gradient (Line one two) = (y two - y one) / (x two - x one)
但是我们可以更深一层,而无需使用过多的括号,因为x
和y
.
asFunction :: Line -> (Double -> Double) -- ( ) for clarity, not necessity
asFunction l@(Line point _) = \xx -> gradient l * (xx - x point) + y point
请注意,我曾经l@
引入一个别名(Line point _)
来保存右侧的输入。
现在我们可以使用中缀函数技巧来去掉更多的括号:
onLine :: Line -> Point -> Bool
onLine l p = l `asFunction` x p `is` y p
在右侧,您可以使用$
去掉括号,但在模式匹配中不能在左侧使用它,因为它是一个函数f $ x = f x
。例如
this (that (the other thing (something other)))
= this $ that $ the other thing $ something other
= this . that . the other thing $ something other
摆脱括号的另一种方法是在多个 case 表达式中进行模式匹配:
onLine l p = case l of
Line p1 p2 -> case p1 of
Point x1 y1 -> case p2 of
Point x2 y2 -> case p of
Point x y -> True -- you can use x1,y1,x2,y2,x and y here
这与编译器将模式匹配“翻译”成的内容接近,但当然这并没有太大的改进!
但是,有许多编写此表达式的方法也可以转换为相同的级联模式匹配;这是一个:
onLine l p = let
Line (Point x1 y1) (Point x2 y2) = l
Point x y = p
in True
这是另一个:
onLine l p = True where
Line (Point x1 y1) (Point x2 y2) = l
Point x y = p
在我看来,最后一个非常好且易读,但其他建议要好得多,因为它们会带来更好的结构化程序!
(有一些关于无可辩驳的模式的东西,我正在掩饰,这仅适用于单构造函数数据类型)
您可以通过定义访问器在函数中将线和点分开,但是没有括号就无法进行模式匹配。