As a training exercise, I have written a polymorphic function to determine whether a given number is prime to either a single number or all of a list of numbers:
{-# LANGUAGE FlexibleInstances #-}
class PrimeTo a where
ispt :: Integer -> a -> Bool
instance PrimeTo (Integer) where
ispt n d = 0 /= (rem n d)
instance PrimeTo ([Integer]) where
ispt n [] = True
ispt n (x:xs) = (ispt n x) && (ispt n xs)
To get this to work, I had to use FlexibleInstances, and I'm happy with that, but curious.
Under strict Haskell 98, as I understand it, I would need to add a type descriptor, T, to the instance definitions:
class PrimeTo a where
ispt :: Integer -> a -> Bool
instance PrimeTo (T Integer) where
ispt n d = 0 /= (rem n d)
instance PrimeTo (T [Integer]) where
ispt n [] = True
ispt n (x:xs) = (ispt n x) && (ispt n xs)
but I haven't a clue what goes in place of "T", and I don't even know whether this is possible under Haskell 98.
So:
T
can be Integer
or []
, as folllows:
class PrimeTo a where
ispt :: Integer -> a -> Bool
instance PrimeTo Integer where
ispt n d = 0 /= (rem n d)
instance PrimeToList a => PrimeTo [a] where
ispt = isptList -- see below
Since the last one can only be about [a]
, we need a helper class PrimeToList
.
Here's the additional helper class and instance:
class PrimeToList a where
isptList :: Integer -> [a] -> Bool
instance PrimeToList Integer where
isptList n [] = True
isptList n (x:xs) = ispt n x && isptList n xs
By the way, I'd rewrite the last definition using all
:
isptList n = all (ispt n)
The above shows the general technique. In your specific case, you can probably avoid the helper class and use
class PrimeTo a where
ispt :: Integer -> a -> Bool
instance PrimeTo Integer where
ispt n d = 0 /= (rem n d)
instance PrimeTo a => PrimeTo [a] where
ispt n = all (ispt n)
This will also define PrimeTo [[Integer]]
, PrimeTo [[[Integer]]]
and so on, so it is not a perfect replacement like the previous one.