在Haskell中测试四个点是否形成正方形
在一个网站上,我发现了以下挑战,被抓住了,我不知道如何解决它。我们需要定义以下函数:在Haskell中测试四个点是否形成正方形,haskell,Haskell,在一个网站上,我发现了以下挑战,被抓住了,我不知道如何解决它。我们需要定义以下函数: isSquare::(数a,词a)=>(a,a)->(a,a)->(a,a)->(a,a)->Bool 这样,当点是正方形的顶点时返回True,当点不是正方形的顶点时返回False isSquare (1,1) (1,1) (1,1) (1,1) == True isSquare (0,0) (0,2) (3,2) (3,0) == False isSquare (0,0) (3,4) (8,4)
isSquare::(数a,词a)=>(a,a)->(a,a)->(a,a)->(a,a)->Bool
这样,当点是正方形的顶点时返回True,当点不是正方形的顶点时返回False
isSquare (1,1) (1,1) (1,1) (1,1) == True
isSquare (0,0) (0,2) (3,2) (3,0) == False
isSquare (0,0) (3,4) (8,4) (5,0) == False
isSquare (0,0) (0,0) (1,1) (0,0) == False
我试过这个:
True
如果有点p1、p2、p3和p4,则计算距离d1=| p1 p2 |,d2=|p1 p3 |,d3=| p1 p4 |,d4=| p2 p3 |,d5=| p2,p4 |,d6=| p3 p4 |。(您还可以计算距离的平方…) 看看你得到了多少不同的距离值。如果只有两个不同的值,则一个用于4条边的长度,另一个用于2条对角线的长度,并且有一个正方形 如果有两个以上的不同值,则它不是正方形
实现提示:创建一个距离列表,然后查看列表函数。如果有点p1、p2、p3和p4,则计算距离d1=| p1 p2 |,d2=| p1 p3 |,d3=| p1 p4 |,d4=| p2 p3 |,d5=| p2,p4 |,d6=| p3 |。(您还可以计算距离的平方…) 看看你得到了多少不同的距离值。如果只有两个不同的值,则一个用于4条边的长度,另一个用于2条对角线的长度,并且有一个正方形 如果有两个以上的不同值,则它不是正方形
实现提示:创建一个距离列表,然后查看列表函数。我确信有很多方法可以解决这个问题,但这是我第一次想到的方法
import Data.Functor
import Data.Maybe
import Control.Applicative
import Control.Monad
首先,让我们为二维向量定义一个类型,并对其进行一些基本操作。我们需要能够加和减,并使用点积来测试正交性
data V2 a = V2 a a
deriving Eq
(^+), (^-) :: Num a => V2 a -> V2 a -> V2 a
V2 x y ^+ V2 x' y' = V2 (x + x') (y + y')
V2 x y ^- V2 x' y' = V2 (x - x') (y - y')
infixl 6 ^+, ^-
dotProduct :: (Num a) => V2 a -> V2 a -> a
dotProduct (V2 x y) (V2 x' y') = (x * x') + (y * y')
orthogonal :: (Eq a, Num a) => V2 a -> V2 a -> Bool
orthogonal a b = dotProduct a b == 0
我们还将定义一条线段:
data LineSegment a = LineSegment (V2 a) (V2 a)
isSquare
函数将首先获取前三个点,并查看它们是否形成直角三角形。让我们定义一个直角三角形类型,以及一个函数,如果三个点之间有直角,则将它们转换为直角三角形
data RightTriangle a =
RightTriangle
(V2 a) -- Point at the right angle
(LineSegment a) -- Hypotenuse
rightTriangleMaybe :: (Eq a, Num a)
=> V2 a -> LineSegment a -> Maybe (RightTriangle a)
rightTriangleMaybe x hyp@(LineSegment a b) =
guard (orthogonal (x ^- a) (x ^- b)) $> RightTriangle x hyp
rightTriangleMaybe' :: (Eq a, Num a)
=> V2 a -> V2 a -> V2 a -> Maybe (RightTriangle a)
rightTriangleMaybe' a b c =
rightTriangleMaybe a (LineSegment b c) <|>
rightTriangleMaybe b (LineSegment a c) <|>
rightTriangleMaybe c (LineSegment a b)
我相信有很多方法可以解决这个问题,但这是我第一次想到的
import Data.Functor
import Data.Maybe
import Control.Applicative
import Control.Monad
首先,让我们为二维向量定义一个类型,并对其进行一些基本操作。我们需要能够加和减,并使用点积来测试正交性
data V2 a = V2 a a
deriving Eq
(^+), (^-) :: Num a => V2 a -> V2 a -> V2 a
V2 x y ^+ V2 x' y' = V2 (x + x') (y + y')
V2 x y ^- V2 x' y' = V2 (x - x') (y - y')
infixl 6 ^+, ^-
dotProduct :: (Num a) => V2 a -> V2 a -> a
dotProduct (V2 x y) (V2 x' y') = (x * x') + (y * y')
orthogonal :: (Eq a, Num a) => V2 a -> V2 a -> Bool
orthogonal a b = dotProduct a b == 0
我们还将定义一条线段:
data LineSegment a = LineSegment (V2 a) (V2 a)
isSquare
函数将首先获取前三个点,并查看它们是否形成直角三角形。让我们定义一个直角三角形类型,以及一个函数,如果三个点之间有直角,则将它们转换为直角三角形
data RightTriangle a =
RightTriangle
(V2 a) -- Point at the right angle
(LineSegment a) -- Hypotenuse
rightTriangleMaybe :: (Eq a, Num a)
=> V2 a -> LineSegment a -> Maybe (RightTriangle a)
rightTriangleMaybe x hyp@(LineSegment a b) =
guard (orthogonal (x ^- a) (x ^- b)) $> RightTriangle x hyp
rightTriangleMaybe' :: (Eq a, Num a)
=> V2 a -> V2 a -> V2 a -> Maybe (RightTriangle a)
rightTriangleMaybe' a b c =
rightTriangleMaybe a (LineSegment b c) <|>
rightTriangleMaybe b (LineSegment a c) <|>
rightTriangleMaybe c (LineSegment a b)
我们创建一个函数,返回两点之间的笛卡尔距离:
dist (x1, y1) (x2, y2) = sqrt $ (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
我们可以从每个点计算到其他三个点的距离
对于正方形,这些距离对于每个点都是相同的,其形式为[a,a,sqrt(2*a^2)]
。可以测试以下各项,以确定给定的点集形成正方形:
- 所有的距离列表都是相同的
- 较短的两个距离相等
- 最长距离=sqrt(2*a^2),其中a是短距离
(0,0)(0,1)(1,1)(1,0)
点(0,0)的排序距离列表为[1,1,1.414]
* distance to (0,1) = 1
* distance to (1,0) = 1
* distance to (1,1) = sqrt(2) ~ 1.414
同样,所有其他点的距离列表为[1,1,1.414]
* distance to (0,1) = 1
* distance to (1,0) = 1
* distance to (1,1) = sqrt(2) ~ 1.414
我们通过映射列表上的部分距离函数来计算距离,然后进行排序,以确保较短的距离位于头部
然后我们可以查看距离列表,确保前两个元素相等
d1!!0 == d1!!1
对角线距离等于两条边距离平方和的平方根
sqrt((d1!!0)^2+(d1!!1)^2) == d1!!2
您可以将最后一个条件等效为
(d1!!0)^2+(d1!!1)^2 == (d1!!2)^2
实际上,正如user@dfeuer所指出的,我们可以使用平方距离来建立一组点,即一个正方形。然后,这些函数可以写成
dist (x1, y1) (x2, y2) = (x2-x1)^2 + (y2-y1)^2
isSquare (x1,y1) (x2,y2) (x3,y3) (x4,y4) =
let m1 = dist (x1,y1)
m2 = dist (x2,y2)
m3 = dist (x3,y3)
m4 = dist (x4,y4)
d1 = sort $ map m1 [(x2,y2),(x3,y3),(x4,y4)]
d2 = sort $ map m2 [(x1,y1),(x3,y3),(x4,y4)]
d3 = sort $ map m3 [(x1,y1),(x2,y2),(x4,y4)]
d4 = sort $ map m4 [(x1,y1),(x2,y2),(x3,y3)]
in d1 == d2 && d2 == d3 && d3 == d4 && d1!!0 == d1!!1 && 2*d1!!0 == d1!!2
我们创建一个函数,返回两点之间的笛卡尔距离:
dist (x1, y1) (x2, y2) = sqrt $ (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)
我们可以从每个点计算到其他三个点的距离
对于正方形,这些距离对于每个点都是相同的,其形式为[a,a,sqrt(2*a^2)]
。可以测试以下各项,以确定给定的点集形成正方形:
- 所有的距离列表都是相同的
- 较短的两个距离相等
- 最长距离=sqrt(2*a^2),其中a是短距离
(0,0)(0,1)(1,1)(1,0)
点(0,0)的排序距离列表为[1,1,1.414]
* distance to (0,1) = 1
* distance to (1,0) = 1
* distance to (1,1) = sqrt(2) ~ 1.414
同样,所有其他点的距离列表为[1,1,1.414]
* distance to (0,1) = 1
* distance to (1,0) = 1
* distance to (1,1) = sqrt(2) ~ 1.414
我们通过映射列表上的部分距离函数来计算距离,然后进行排序,以确保较短的距离位于头部
然后我们可以查看距离列表并确保