这是同一列表的另一种排序方式(根据 hammar 的建议):
-- the integer points along the diagonals of slope -1 on the cartesian plane,
-- organized by x-intercept
-- diagonals = [ (0,0), (1,0), (0,1), (2,0), (1,1), (0,2), ...
diagonals = [ (n-i, i) | n <- [0..], i <- [0..n] ]
-- the multiples of three paired with the squares
paar = [ (3*x, y^2) | (x,y) <- diagonals ]
在行动中:
ghci> take 10 diagonals
[(0,0),(1,0),(0,1),(2,0),(1,1),(0,2),(3,0),(2,1),(1,2),(0,3)]
ghci> take 10 paar
[(0,0),(3,0),(0,1),(6,0),(3,1),(0,4),(9,0),(6,1),(3,4),(0,9)]
ghci> elem (9, 9801) paar
True
通过使用对角线路径遍历所有可能的值,我们保证我们在有限的时间内到达每个有限的点(尽管有些点仍然在内存的范围之外)。
正如 hammar 在他的评论中指出的那样,这还不够,因为它仍然需要
获得False 答案的无限时间。
但是,我们对 paar 的元素有一个顺序,即 (3*a,b^2) 在 (3*c,d^2) 之前
a + b < c + d。所以要确定给定的对 (x,y) 是否在 paar 中,我们只需要检查
将(p,q) 与p/3 + sqrt q <= x/3 + sqrt y 配对。
为避免使用Floating 数字,我们可以使用稍微宽松的条件,即p <= x || q <= y。
当然p > x && q > y 暗示p/3 + sqrt q > x/3 + sqrt y,所以这仍然会包括任何可能的解决方案,并且保证会终止。
所以我们可以在里面构建这个检查
-- check only a finite number of elements so we can get a False result as well
isElem (p, q) = elem (p,q) $ takeWhile (\(a,b) -> a <= p || b <= q) paar
并使用它:
ghci> isElem (9,9801)
True
ghci> isElem (9,9802)
False
ghci> isElem (10,9801)
False