Brent.Longborough
Brent.Longborough

Reputation: 9775

How to code polymorphic functions under Haskell 98

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:

  1. Is this even possible under Haskell 98?
  2. If so, what would be used for T?

Upvotes: 2

Views: 84

Answers (1)

chi
chi

Reputation: 116174

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.

Upvotes: 4

Related Questions