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的调用返回的值与第一次调用的返回值不同,则对all的调用结束(第 4 行)。同样,我想要一种以惰性方式生成vertexPairs列表的方法。


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

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

2 回答 2

4

虽然 tikhon 已经回答了大多数问题,但如果你想以更漂亮的方式编写它,你可以这样做

vertexPairs v = zip v (tail $ cycle v)

这是有效的,因为zip当其中一个参数“用完”时停止生成列表

于 2013-04-28T17:07:45.207 回答
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因为相反的转换(将期望元组的函数转换为多个参数之一)称为柯里化。所以你可以写 3. 像这样:

results = map (uncurry (isInside point)) vertexPairs
于 2013-04-28T16:59:46.727 回答