Struggling with Haskell type system - haskell

I am trying to learn some Haskell by doing basic tasks in the particular case I am trying to implement some basic function for primality check, but I really can figure out the types, my code is
isPrime :: (Num a) => a -> Bool
isPrime n
| n <= 1 = False
| otherwise = not $ 0 `elem` map (mod n) [2..m] where m = floor $ sqrt n
I tried instead of (Num a) => a to use different number types or to use sqrt with fromIntegral but I still get error messages, like:
*Could not deduce (Floating a) arising from a use of `sqrt'
from the context: Num a
bound by the type signature for:
isPrime :: forall a. Num a => a -> Bool
at Helpers.hs:5:1-31
Possible fix:
add (Floating a) to the context of
the type signature for:
isPrime :: forall a. Num a => a -> Bool
* In the second argument of `($)', namely `sqrt n'
In the expression: floor $ sqrt n
In an equation for `m': m = floor $ sqrt n
| otherwise = not $ 0 `elem` map (mod n) [2..m] where m = floor $ sqrt n
I can really use some help here, thank you in advance.

As others have mentioned, the use of mod requires a to be Integral, and the use of sqrt requires a to be Floating. Judging by the name of your function, I'm assuming that you want to use it on integral types.
So, you can fix this by changing your signature to isPrime :: (Integral a) => a -> Bool, then precomposing sqrt with fromIntegral. You could do something like
where m = floor . sqrt . fromIntegral $ n
Another option would be to replace [1..m] with something like takeWhile (\x -> x * x <= n) [1..] to avoid the need for Floating.

You have two problems in your code:
Incompatible types.
Calling both sqrt n and (mod n) reqiure n to be both Floating and Integral at the same time.
Insufficient context. Requiring only (Num a) does not allow neither of the operations.
A possible fix would be: a) narrow down type context to a much more concise (Integral a); b) add fromIntegral to sqrt's argument:
isPrime :: Integral a => a -> Bool
isPrime n
| n <= 1 = False
| otherwise = not $ 0 `elem` map (mod n) [2..m] where m = floor $ sqrt $fromIntegral n

The issue the compiler is describing is that you're applying incompatible operations to the same type: mod requires Integral a, sqrt requires Floating a, and no type satisfies both. You could work around that using type conversions like fromIntegral and ceiling, but you'd want to be careful to avoid rounding errors. For my test, I removed the type constraint and used m = ceiling $ sqrt $ fromIntegral n, which led to the inferred type isPrimeSqrt :: Integral a => a -> Bool.
Another approach is to consider why the conflict was hit and look for other solutions. The reason for sqrt is to produce an optimized stopping point for the test. Can we find that stopping point in another manner?
As it turns out, while division is expensive, it frequently produces two results: the quotient and remainder. With mod you're looking for the latter, but we have divMod and quotRem which produce both. So it could be worth testing if that's notably slower than the plain mod test (benchmark results, comparing [2..] vs [2..m]).
isPrime n = (n > 1) && null (filter isFactor (takeWhile notTooHigh divisors))
where notTooHigh (divisor,quotient,_) = divisor <= quotient
isFactor (_,_,remainder) = remainder == 0
divisors = [(divisor,quotient,remainder) |
divisor <- 2:[3,5..],
let (quotient,remainder) = quotRem n divisor]

Related

Why is `fmap` needed to call `succ` on a `Maybe Integer`?

I am brand new to Haskell and am working on a practice Collatz conjecture problem. The required output is the number of steps needed to get to 1 from a given integer. This is the first time I've had to use the Maybe type, which may be contributing to my confusion.
I have this working solution based on another solution I found to the same problem:
collatz :: Integer -> Maybe Integer
collatz n
| n <= 0 = Nothing
| n == 1 = Just 0
| even n = fmap succ . collatz $ n `div` 2
| otherwise = fmap succ . collatz $ 3 * n + 1
What is unclear to me is why it is necessary to use fmap succ in this situation. Based on my current understanding, I would expect to just be able to call succ on the output of the recursive call to collatz in order to increment it; however, this throws an error:
> No instance for (Enum (Maybe Integer))
arising from a use of `succ'
It looks like the error has something to do with calling succ on a Maybe Integer type instead of an Integer. Is the error because a Maybe Integer isn't considered enumerable in Haskell? If so why does calling fmap succ solve this problem?
If you just start learning Haskell, using . and $ needlessly present an additional cognitive load for you. What you have is simpler written as
collatz :: Integer -> Maybe Integer
collatz n
| n <= 0 = Nothing
| n == 1 = Just 0
| even n = fmap succ (collatz (n `div` 2))
| otherwise = fmap succ (collatz (3 * n + 1))
Now, what is succ? If we look at its type,
> :t succ
succ :: Enum a => a -> a
the main thing to notice is that the input and the output types are one and the same. It is also an instance of the Enum class of types, which is just to say that this type implements its specific version of the succ function (it's a bit circular that way).
Since we're dealing with Integers, which do implement their version of succ as
succ :: Integer -> Integer
succ i = i + 1
it's all good and taken care of.
Except collatz :: Integer -> Maybe Integer takes an Integer and returns a Maybe Integer:
-- pseudocode
Maybe Integer = Nothing
| Just Integer
-- ^ tags ^ types of contained data
So we need to apply succ to the contained Integer. And that's the job of fmap:
-- pseudocode
> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
> :t fmap # Maybe
fmap :: (a -> b) -> Maybe a -> Maybe b
> :t fmap # Maybe succ # Integer
fmap :: Maybe Integer -> Maybe Integer
Which is a generic function defined by a class of types that each define their specialized version of it. As Maybe indeed does:
-- pseudocode:
fmap f Nothing = Nothing
fmap f (Just i) = Just (f i)
-- ^^ f applied on the "inside"
-- ^^ when there is something in there

Haskell - From generic to Integer | No instance for (RealFrac Integer) arising from a use of ‘floor’

I'm learning haskell.
I'm trying to solve a problem in which you're given a number (n) and you have to find a pair (m, k) where m^k would make n a perfect power.
n is a perfect power if there exist natural numbers m > 1, and k > 1
such that m^k = n.
This is what I came up with so far
module Test where
isPerfectPowerOf :: (Floating p, Enum p, RealFrac p) => p -> Maybe [(p, p)]
isPerfectPowerOf i
| null perfectList = Nothing
| otherwise = Just perfectList
where perfectList = filter (\(x, _) -> floor x == x) [(logBase x i, x) | x <- [2 .. (i - 1)]]
and it works.
But as you can see, with very generic types. What I want is for it to work with
isPerfectPowerOf :: Integer -> Maybe [(Integer, Integer)]
So for debugging purposes I placed this signature over the code which gave me these errors
severity: 'Error'
message: ' • No instance for (RealFrac Integer) arising from a use of ‘floor’
• In the first argument of ‘(==)’, namely ‘floor x’
In the expression: floor x == x
In the first argument of ‘filter’, namely
‘(\ (x, _) -> floor x == x)’
severity: 'Error'
message: ' • No instance for (Floating Integer)
arising from a use of ‘logBase’
• In the expression: logBase x i
In the expression: (logBase x i, x)
In the second argument of ‘filter’, namely
‘[(logBase x i, x) | x <- [2 .. (i - 1)]]’
So if I'm not completely off the mark I'll need to somehow typecast floor's and logBase's inputs properly.
floor :: (RealFrac a, Integral b) => a -> b
logBase :: Floating a => a -> a -> a
How should I go about doing it?
Or if it isn't the problem what could be?
So you tried:
perfectList :: Integer -> [(Integer, Integer)]
perfectList i = filter (\(x, _) -> floor x == x) [(logBase x i, x) | x <- [2 .. (i - 1)]]
(I'm going to deal with perfectList here for the sake of brevity. Note, though, that the conversion to Maybe in isPerfectPowerOf is perhaps redundant, as the nothingness of the Maybe result is equivalent to the emptiness of the list.)
That results in the two type errors you quoted. The first one arises because the argument to floor must be of some RealFrac type, and Integral isn't one of them. Similarly, the second error arises because logBase takes and returns values of some Floating type (and so you need to not only convert the arguments to floating-point but also convert the result back to Integer). Performing these adjustments results in:
perfectList :: Integer -> [(Integer, Integer)]
perfectList i = fmap (\(k, x) -> (floor k, x))
. filter (\(k, _) -> fromIntegral (floor k) == k)
$ [(logBase (fromIntegral x) (fromIntegral i), x) | x <- [2 .. (i - 1)]]
(Note that I have renamed your log variable, for the sake of clarity; you might also want to swap the order of the elements in the pairs.)
Since you are using a list comprehension already, it is easier to shift the fmap and the filter into it:
perfectList :: Integer -> [(Integer, Integer)]
perfectList i = [(k', x) | x <- [2 .. (i - 1)]
, let k = logBase (fromIntegral x) (fromIntegral i), let k' = floor k
, fromIntegral k' == k
]
On a final note, using floor to check whether a floating-point number is "really" a round number isn't fully reliable:
GHCi> fromIntegral (floor (logBase 2 (2**29))) == logBase 2 (2**29)
False
That being so, an ultimately sounder approach would be switching to an algorithm that finds perfect powers using integer arithmetic throughout, thus avoiding floating-point altogether. (While I suspect you'd want to implement that yourself, for an off-the-shelf solution check the Math.NumberTheory.Powers module from the arithmoi package.)

Ambiguous type variable in combination of sqrt and floor

Trying to implement a function for listing all prime numbers in some range of numbers, I know when I am checking for factors I do not have to check beyond the sqrt of that that number.
factors n = [x | x <- [1..(floor (sqrt n))], mod n x == 0]
prime n = factors n == [1,n]
listPrimesFromTill n z = [ xs | xs <- [n..z], prime xs == True]
I've been browsing for answers and I tried various methods like type checking using
factors :: (RealFrac b, Integral c, Floating b) => b -> c
but have had no luck.
Any help is appreciated!
It seems like you looked at the code you wrote and figured the types out after. In general, Haskell development is the other way around: First you figure out the types, then you implement the functions. What type should factors have? Well, you can only factorize integers, so something of type, so this seems sensible:
factor :: Integral a => a -> [a]
Now when trying to compile your code we get the following error:
Could not deduce (Floating a) arising from a use of `sqrt` from the context (Integral a)
and
Could not deduce (RealFrac a) arising from a use of `sqrt` from the context (Integral a)
It complains that you specified Integral a but it needs Floating a for sqrt. We can do this by usinf fromIntegral:
sqrt :: Floating a => a -> a
fromIntegral :: (Integral a, Num b) => a -> b
factors :: Integral a => a -> [a] vvvvvvvvvvvvvv
factors n = [x | x <- [1..(floor (sqrt (fromIntegral n)))], mod n x == 0]
To preserve readability,
factors n = [x | x <- [1..isqrt n], mod n x == 0]
where isqrt = floor . sqrt . fromIntegral

Apply comparison between Integral and Fractional

I want to check if an Integral is a square:
isSquare :: Integral n => n -> Bool
isSquare n = (>1) $ length (filter (\x -> n / x == x) numList)
where numList = reverse [1..n]
Apart from whether or not iterating through a list is the right approach here, when I try to compile this function I get the error:
No instance for (Fractional Int) arising from a use of ‘/’
My understanding of this is that since I am binding n to the Integral type, by dividing it I am breaking the function's rigid type construction. How can I fix my function so that it compiles?
You could add fromIntegral to everything to get Fractionals:
filter (\x -> fromIntegral n / fromIntegral x == fromIntegral x) numList
Or just square the number instead:
filter (\x -> n == x ^ 2)
Also, your length check shouldn’t be >1. ==1 would make more sense, but you should use null to avoid having to try every number every time (besides using a faster algorithm in the first place).
isSquare :: Integral a => a -> Bool
isSquare n = not $ null $ filter (\x -> n == x ^ 2) numList
where numList = [n,n-1..1]

GHC not deducing the way I would like it to :-(

chainQuery :: (Enum a, Integral a, Ord b) => a -> b -> [c]
chainQuery n min = map length $ filter beatingLength $ map chain [1..n]
where
beatingLength :: [a] -> Bool
beatingLength xs = length xs > min
chain :: (Integral a) => a -> [a]
chain n
| n <= 1 = [n]
| even n = n:(chain $ div n 2)
| otherwise = n:(chain $ n * 3 + 1)
In the code sample above why isn't GHC able to deduce that 'c' is an Int by looking at the type definition for length?
Why does GHC need to know anything about 'b' other than that it is an Ord?
Is there a better way to write this function?
GHC is able to infer [Int] as the result type for the function. The problem is that you've claimed in your type signature that it should be more polymorphic, that the result could be a list of any type, which does not make sense since the return value comes from the map length so it must have type [Int]. This is what GHC is complaining about when it says Could not deduce (c ~ Int).
You're comparing min to length xs. The greater-than operator has the type (>) :: (Ord a) => a -> a -> Bool, which means that both sides must be the same type. The type of length xs is Int, so this forces min to be Int as well.
Probably. For example, you can map the length before doing the filtering. This makes it easy to use an operator section instead of your beatingLength function. You can also move the parenthesis to save a use of $ to make the code a bit neater.
chainQuery n min = filter (> min) $ map (length . chain) [1..n]
where chain n | n <= 1 = [1]
| even n = n : chain (n `div` 2)
| otherwise = n : chain (3*n + 1)
For reference, the easiest way to solve a problem like this is to remove your type signature and see what type was inferred in GHCi using the :t command. In this case, the inferred type is
*Main> :t chainQuery
chainQuery :: Integral a => a -> Int -> [Int]

Resources