Haskell函数测试Int是否是使用无限列表的完美正方形

时间:2013-04-26 04:02:04

标签: haskell

纯粹为了快乐和练习,我试图编写一个简单的Haskell函数来确定整数是否是一个完美的正方形。现在我知道还有其他解决方案,但我想知道是否有办法用无限列表来做到这一点。我已经从这开始,但由于明确的原因,它不起作用(它永远不会停止!)

    isSquare :: Integer -> Bool
    isSquare n = sum[ 1 | x <- [1..], x*x == n] /= 0

另外,如果我可以添加,有人可以指出如何搜索无限列表中的第一个实例,然后停止! ?

5 个答案:

答案 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)

您可以使用takeWhiledropWhile。例如:

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