纯粹为了快乐和练习,我试图编写一个简单的Haskell函数来确定整数是否是一个完美的正方形。现在我知道还有其他解决方案,但我想知道是否有办法用无限列表来做到这一点。我已经从这开始,但由于明确的原因,它不起作用(它永远不会停止!)
isSquare :: Integer -> Bool
isSquare n = sum[ 1 | x <- [1..], x*x == n] /= 0
另外,如果我可以添加,有人可以指出如何搜索无限列表中的第一个实例,然后停止! ?
答案 0 :(得分:11)
关于无限搜索功能:
已经有一个功能可以在列表中搜索值 - elem
。
如果您假设无限列表已排序,我们可以编写一个适用于此类列表的elem版本。这可以通过首先拒绝任何小于搜索值的元素来轻松完成。然后,未被拒绝的第一个值必须等于或大于搜索元素。如果相等 - 返回true,否则返回false
infiniteElem1 :: (Ord a) => a -> [a] -> Bool
infiniteElem1 x list = (== x) $ head $ dropWhile (< x) list
使用示例:
> infiniteElem1 10 [1..]
True
> infiniteElem1 10 [1,3..]
False
但是infiniteElem1
有一个问题:如果在有限列表中使用,如果找不到该元素,它可能会抛出异常:
> infiniteElem1 100 [1,2,3]
*** Exception: Prelude.head: empty list
这是最好避免使用函数head
的原因。更好的解决方案是:
infiniteElem :: (Ord a) => a -> [a] -> Bool
infiniteElem x list = case dropWhile (< x) list of
[] -> False
(v:_) -> v == x
现在它也适用于有限排序列表:
> infiniteElem 100 [1,2,3]
False
这样你的问题就变得微不足道了:
let isSquare n = n `infiniteElem` [ x * x | x <- [1..]]
答案 1 :(得分:6)
您可以使用takeWhile
或dropWhile
。例如:
isSquare n = head (dropWhile (< n) squares) == n
where squares = [x*x | x <- [0..]]
答案 2 :(得分:5)
不幸的是,在无限列表中使用Sum是行不通的。特别是,你怎么知道列表的每个未来元素都将为零?你不能,所以你必须在计算总和之前得到整个清单。对于无限列表,这可能需要一段时间。
如果你真的想要使用无限列表 - 无限列表 很有趣,毕竟 - 我建议构建一个无限的方数列表。然后检查n
是否在该列表中。你必须对你如何做到这一点有点聪明,以确保它终止,但我会把它作为练习留给读者。 (伙计,我喜欢这句话:P。)
您可以使用类似,可预测的find
等函数从无限列表中找到某些内容。一旦发现某事,它实际上就会停止。但是,如果没有找到该元素,它将永远不会停止。这可能不是您想要的行为。没有解决这个问题的一般方法,但您可以弄清楚如何解决任何特定问题:例如,如果列表按升序排序,您可以执行takeWhile (< limit)
其中limit
是可能答案的上限。
答案 3 :(得分:4)
let isSquare n = elem n (takeWhile (<=n) [ x*x | x <- [1..]])
ghci> isSquare 25
True
ghci> isSquare 28
False
答案 4 :(得分:4)
只是为了好玩,这是另一个无限列表版本:
isSquare n = isSquare' [1..] where
isSquare' infiniteList@(x:xs)
| x*x == n = True
| x*x > n = False
| otherwise = isSquare' xs