Adding a Show constraint when using GHC.Generics

62 Views Asked by At

I am using GHC Generics. My use case is almost identical to the example in the wiki, except that I am encoding and decoding gene sequences.

This was all working fine, until I decided to keep a list of what I'd already read, so that I could report it to the user in case of an error. That means that I need to add a Show constraint to my default get implementation. The problem is that I can't figure out how to write the constraint. See the -- HELP!!! comment in the code below.

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE TypeOperators #-}

import Control.Monad.State.Lazy (StateT)
import qualified Control.Monad.State.Lazy as S (put, get, gets)
import Data.Functor.Identity (Identity)
import Data.Word (Word8, Word16)
import GHC.Generics

type Sequence = [Word8]

type Writer = StateT Sequence Identity

type Reader = StateT (Sequence, Int, [String]) Identity

class Genetic g where
  -- | Writes a gene to a sequence.
  put :: g -> Writer ()

  default put :: (Generic g, GGenetic (Rep g)) => g -> Writer ()
  put = gput . from

  -- | Reads the next gene in a sequence.
  get :: Reader (Either [String] g)

  default get :: (Generic g, GGenetic (Rep g), Show (Rep g x???)) -- HELP!!!
    => Reader (Either [String] g)
  get = do
    (_, start, _) <- S.get
    a <- gget
    (xs, stop, trace) <- S.get
    let msg = show start ++ ':' : show stop ++ ' ' : show a
    S.put (xs, stop, msg:trace)
    return $ fmap to a

class GGenetic f where
  gput :: f a -> Writer ()
  gget :: Reader (Either [String] (f a))
1

There are 1 best solutions below

0
On BEST ANSWER

D'oh! I should have used show (fmap to a) instead of show a.Then all I needed was to add Show g as a constraint.. This simple change compiles fine:

  default get :: (Generic g, GGenetic (Rep g), Show g)
                => Reader (Either [String] g)
  get = do
    (_, start, _) <- S.get
    a <- gget
    (xs, stop, trace) <- S.get
    let result = fmap to a
    let msg = show start ++ ':' : show stop ++ ' ' : show result
    S.put (xs, stop, msg:trace)
    return result