Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell typeclass and duplicate behaviour

I'm new to Haskell & trying to generalise some behaviour in a program so as to reduce the amount of code and have a simpler solution overall.

Say I have this type which represents a post code e.g. 'ABC 123':

type PostCode = ((Char, Char, Char), (Int, Int, Int))

and the behaviour of a PostCode should be cylic; i.e. AAA 000 comes before AAA 001; 'A' to 'Z' for Char should rap-round, as should 0-9 for Int.

I've therefore extraced this type class:

class Cyclic a where
    next :: a -> a

which is simple enough.

So I then have an instance for each:

-- import Data.Char
instance Cyclic Char where
    next c = chr n
      where nxt = (ord c) + 1
            min  = 65
            max  = 90
            n    = if (nxt > max) then min else nxt

instance Cyclic Int where
    next i = n
      where nxt = i + 1
            min  = 0
            max  = 9
            n    = if (nxt > max) then min else nxt

which leaves me with several obvious points:

  • the concept of min and max is duplicated

  • next is reimplemented for Int when the only real difference is the values of its min and max, as well as the type

How can I abstract this behaviour correctly? Is there a way to have the cyclic behaviour for both Int and Char without having two differing implementations? What other Haskell features might I use instead?

like image 598
Alex Avatar asked Apr 28 '26 22:04

Alex


1 Answers

You can provide a default implementation for next in the type-class as in:

import Data.Char (chr)

class (Ord a, Enum a) => Cyclic a where
    min', max' :: a
    next :: a -> a
    next a = if max' < a' then min' else  a'
        where a' = succ a

instance Cyclic Char where
    min' = chr 65
    max' = chr 90

instance Cyclic Int where
    min' = 0
    max' = 9

Alternatively you can use a helper function which implements next within a closure as in:

class Cyclic a where
    next :: a -> a

-- a helper function to implement next within a closure
cycl :: (Ord a, Enum a) => a -> a -> (a -> a)
cycl min' max' a = if max' < a' then min' else a'
    where a' = succ a

instance Cyclic Char where
    next = cycl (chr 65) (chr 90)

instance Cyclic Int where
    next = cycl 0 9
like image 186
behzad.nouri Avatar answered Apr 30 '26 11:04

behzad.nouri



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!