Purely for pleasure, and practice, I am trying to write a simple Haskell function to determine if an integer is a perfect square. Now I know that there are other solutions out there but I am wondering if there is a way to do it with an infinite list. I've started with this, but for clear reasons, it is not working (it never stops!)
isSquare :: Integer -> Bool
isSquare n = sum[ 1 | x <- [1..], x*x == n] /= 0
Also, if I might add, can someone point out how to search an infinite list for the first instance of something and then STOP! ?
There's a very simple way to test for a perfect square - quite literally, you check if the square root of the number has anything other than zero in the fractional part of it.
All perfect squares end in 1, 4, 5, 6, 9 or 00 (i.e. Even number of zeros). Therefore, a number that ends in 2, 3, 7 or 8 is not a perfect square.
To check the perfectness of your square, you can simply calculate the square root of a given number. If the square root is an integer, your number is the perfect square. Let's calculate the squares of the following numbers: 49 and 53 . √49 = 7 - 7 is an integer → number 49 is a perfect square.
Suppose we have a number n, we have to check whether n is a perfect square number or not. A perfect square number k can be represented as k = a * a for some integer a. We have to solve this without using built-in square root function. So, if the input is like n = 121, then the output will be True because 121 = 11*11.
About the infinite search function:
There is already a function that searches a list for a value - elem
.
If you assume the infinite list is sorted, we could write a version of elem that works on such a list. This can easily be accomplished by firstly rejecting any elements less than the search value. The first value not rejected then must be either equal to or greater than the search element. If equal - return true, else return false
infiniteElem1 :: (Ord a) => a -> [a] -> Bool
infiniteElem1 x list = (== x) $ head $ dropWhile (< x) list
Example usage:
> infiniteElem1 10 [1..]
True
> infiniteElem1 10 [1,3..]
False
There is one problem though with infiniteElem1
though: If used on a finite list, it may throw an exception if the element isn't found:
> infiniteElem1 100 [1,2,3]
*** Exception: Prelude.head: empty list
This is a reason the function head
is best avoided. A better solution is this:
infiniteElem :: (Ord a) => a -> [a] -> Bool
infiniteElem x list = case dropWhile (< x) list of
[] -> False
(v:_) -> v == x
Now it works with a finite sorted list as well:
> infiniteElem 100 [1,2,3]
False
With this your problem becomes trivial:
let isSquare n = n `infiniteElem` [ x * x | x <- [1..]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With