1
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

有没有办法不使用这么多括号?

4

4 回答 4

5

我推荐一个名为hlint的工具来识别可以简化代码的地方。

在您的代码/所写的/中,您没有使用值、、、、x1或,y1因此您可以只写:x2y2xy

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.

于 2013-07-03T14:29:30.420 回答
3

有时您可以避免使用记录符号、有时使用$、有时使用中缀函数的括号,有时如果不过分也可以。

让我们对点使用记录符号,这对坐标的访问量很大,但我们将不理会Line

data Point = Point {x::Double,y::Double} deriving (Show) 
data Line = Line Point Point deriving (Show)    

这定义了x :: Point -> Doubley :: 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)

但是我们可以更深一层,而无需使用过多的括号,因为xy.

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
于 2013-07-03T15:10:02.397 回答
1

摆脱括号的另一种方法是在多个 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

在我看来,最后一个非常好且易读,但其他建议要好得多,因为它们会带来更好的结构化程序!

(有一些关于无可辩驳的模式的东西,我正在掩饰,这仅适用于单构造函数数据类型)

于 2013-07-03T16:51:32.783 回答
1

您可以通过定义访问器在函数中将线和点分开,但是没有括号就无法进行模式匹配。

于 2013-07-03T14:29:06.840 回答