2013-04-28 105 views
4

要检查光线三角形的碰撞,我们可以先看看光线是否与三角形的平面发生碰撞。如果是这样,我们然后检查交点是否位于所有三角形的同一侧。如果属实,这意味着该点位于三角形内部。此过程类似于矩形和其他凸形图形。在“圆形列表”中懒惰地生成相邻元素对

这是属于矩形(逆时针排序)顶点的列表:

vertexes = [ll, lr, ur, ul] 

,我想生成与它的一切方面的列表;也就是说,所有相邻的一对顶点:

vertexPairs = [(ll, lr), (lr, ur), (ur, ul), (ul, ll)] 

(请注意,最后一个顶点,UL,也对,在第一个,LL

我怎样才能懒洋洋地产生这样的一个通用凸几何图形的列表,假设我有一个有序的顶点列表?


的想法是每对饲料的功能,isInside,并检查是否所有的返回值都是一样的。这是我在做什么:

1. vertexes = [<list of vertexes>] 
2. vertexPairs = ??? 
3. results = map (\(v1, v2) -> isInside point v1 v2) vertexPairs 
4. allequal = all (== head results) (tail results) 

因为Haskell是惰性的,如果isInside一个调用返回,从第一次调用的返回值不同的值,以呼叫中的所有结束(4号线) 。同样,我想以一种懒惰的方式生成列表。


当我写这个问题,我想到了一个可能的解决方案的生成对:

vertexPairs = zip (vertexes) (tail vertexes ++ [head vertexes]) 
  1. 这是懒惰?我会这样说,因为它不使用最后或类似的函数,但我还是比较新的Haskell。
  2. 由于连接和单元素列表,它也看起来有点难看。有没有更好的办法?
  3. 作为一个相关的问题,第3行的自由点符号应该是什么?

回答

3

是的这种生成列表的方式是懒惰的。一般来说,Haskell中的列表函数是懒惰的。

您可以通过在初始列表中包含错误输出的内容(例如undefined)来测试自己是否懒惰。例如,如果

vertexes = [(0,0), (10,0), undefined, undefined] 

然后vertexPairs会给你一个错误(因为它需要评估整个列表打印出来)。但是,如果它很懒,head vertexPairs仍然应该给你正确的一对 - 它的确如此!

我认为你的代码看起来相当不错。 tail vertexes ++ [head vertex]使你的工作非常清晰。是的,在这里使用++看起来有点奇怪,但它是有道理的:追加到列表的末尾是一个昂贵的操作,所以它应该脱颖而出。我想不出有什么更好的方法来编写代码。作为小调式的暗示,你可以删除的括号vertexes

vertexPairs = zip vertexes (tail vertexes ++ [head vertexes]) 

对于3,在概念上,要应用isInside point每对。现在它有一个类型Point -> Point -> Bool。你想得到一个将前两个参数作为元组的函数:(Point, Point) -> Bool。这个函数被称为uncurry,因为相反的转换(将一个元组转换为多个参数之一的函数)被称为currying。所以,你可以写3这样的:

results = map (uncurry (isInside point)) vertexPairs 
+0

非常明确的答案,谢谢。我想这是一件好事,我的解决方案并不是那么糟糕:) – CanisLupus 2013-04-28 17:30:55

4

虽然吉洪回答了大部分问题,如果你想要把它写在一个稍微漂亮的方式,你可以做

vertexPairs v = zip v (tail $ cycle v)

这工作,因为zip当其中一个参数“耗尽”时停止生成列表

+0

嗯,我没有想到:)谢谢! – CanisLupus 2013-04-28 17:35:01

+2

哈,我正要发表评论,但'olianta的反应出现了。我有一个类似的建议,但也是轻浮无点的版本'vertexpairs = zip <*>尾巴。循环'这可能是有趣的 – applicative 2013-04-28 18:52:26