I am updating some code I have. I noticed a lot of repeated code, so I took that as a good sign that some abstraction was needed.
I have several functions that transition a State from one to another. The code to execute the transition is identical for every file.
This:
runOneTest :: Config -> Signal TestResult
runOneTest config = TestResult config <$> result
  where
    result = topEntity startingState inputSignal
    startingState = startS config
    inputSignal   = signal $ input config
What is not identical are the values in the Config Type or the TestResult.
data TestResult = TestResult { initConfig  :: Config
                             , endSt        :: St
                             }deriving (Eq)
data Config = Config { input  :: PIn
                     , startS :: St
                     }deriving (Eq)
More specifically the values that are different are the St(State) and the PIn(PortsIn). Those types can have different values attached.
Example:
data PIn = PIn { _clk   :: Bit
               , _reset :: Bool
               , _start :: Bool
               , _stop  :: Bool
               }
vs
data PIn = PIn { _in_1 :: Bit
               , _clk  :: Bit
               , _reset :: Bool
               } 
I was trying to do that with classes but I am running into problems.
Current:
--------------------------------------------------------------------------------
-- Abstract Area
--------------------------------------------------------------------------------
data TestResult = TestResult { initConfig :: (Transition t) => t
                             , endSt      :: (SysState s) => s
                             }
data Config = Config { input   :: (PortIn p) => p
                     , startSt :: (SysState s) => s
                     }
class (Eq s, Show s) => SysState s
class Transition t where
  runOneTest :: (Transition t) => t -> Signal TestResult
class Result r
class (Eq p, Show p) => PortIn p
--------------------------------------------------------------------------------
-- Stuff to define in each file
--------------------------------------------------------------------------------
runOneTest' :: (Transition t) => t -> Signal TestResult
runOneTest' config = signal $ TestResult config st
data PIn = PIn { _clk   :: Bit
               , _reset :: Bool
               , _start :: Bool
               , _stop  :: Bool
               } deriving (Eq, Show)
instance PortIn PIn
data St = St { _cnt_en   :: Bool
             , _count_us :: BitVector 4
             , _stop_d1  :: Bool
             , _stop_d2  :: Bool
             , _count    :: BitVector 4
             } deriving (Eq, Show)
instance SysState St
st :: St
st = St False 0 False False 0
instance Result TestResult
instance Transition Config where
  runOneTest = runOneTest'
The type of errors I am getting are:
Couldn't match expected type `t1' with actual type `t'
  `t' is a rigid type variable bound by
      the type signature for
        runOneTest' :: Transition t => t -> Signal TestResult
      at ConvertedClashExamples\ClassExample.hs:50:16
  `t1' is a rigid type variable bound by
       a type expected by the context: Transition t1 => t1
       at ConvertedClashExamples\ClassExample.hs:51:31
Relevant bindings include
  config :: t (bound at ConvertedClashExamples\ClassExample.hs:51:13)
  runOneTest' :: t -> Signal TestResult
    (bound at ConvertedClashExamples\ClassExample.hs:51:1)
In the first argument of `TestResult', namely `config'
In the second argument of `($)', namely `TestResult config st'
Original Full Source: https://github.com/LambdaScientist/CLaSH-by-example/tree/master
Note: I looked answers to this question, but I did not find a good enough answer.