在“循环列表”中懒惰生成相邻元素对

时间:2013-04-28 16:44:55

标签: haskell lazy-evaluation circular-list

要检查光线三角形碰撞,我们首先可以看到光线是否与三角形的平面发生碰撞。如果是,我们检查交叉点是否在所有三角形边的同一侧。如果为true,则表示该点位于三角形内。这个过程类似于矩形和其他凸像。

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

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行的自由点表示法应该是什么?

2 个答案:

答案 0 :(得分:4)

虽然tikhon回答了大多数问题,如果你想用稍微漂亮的方式写一下,你可以做到

vertexPairs v = zip v (tail $ cycle v)

这是有效的,因为zip在其中一个参数“耗尽”

时停止生成列表

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