这个Haskell代码中是否需要括号

时间:2013-07-03 14:15:56

标签: haskell

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 个答案:

答案 0 :(得分:5)

我建议使用名为hlint的工具来识别可以简化代码的地方。

在您的代码中/以书面形式/,您没有使用值x1y1x2y2x或{{ 1}},所以你可以写:

y

但是,我认为这只是一个存根,实际上你会对变量做些什么。通常,如果您确实需要引用所有这些变量,那么您需要按照自己的方式编写它。但是,也许您正在使用只需要整个行值的辅助函数。然后你可以这样写:

onLine _ _ = True

或者,您可以使用访问器函数从点和线中提取x和y坐标,但在这种情况下,它可能会使您的代码变得更加混乱。

此外,在Haskell中,我认为使用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 而不是Double通常更有效。

答案 1 :(得分: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

答案 2 :(得分:1)

你可以通过定义访问器来获取行并在函数内分开,但是如果没有括号,就无法进行模式匹配。

答案 3 :(得分: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

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

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