Define a constraint for multiple type variables

Viewed 66

In my codebase I have several types with a different number of type variables.

For example, consider

data MyType a b c = ...
data MyOtherType a b c d e = ...

Then I am defining functions using these types and I want to require that every type variable is an instance of Show.

To avoid too much repetition I used ConstraintKinds to define types

type Show2 a b = (Show a, Show b)
type Show3 a b c = (Show2 a b, Show c)
type Show4 a b c d = (Show3 a b c, Show d)
type Show5 a b c d e = (Show4 a b c d, Show e)

so that in the definition of my functions I can use

f :: (Show5 a b c d e) => MyOtherType a b c d e -> ...

Now my question is: is there a way to simplify the definition of types Show2, ..., Show5? It looks like their definition is recursive and I was wondering if there was an extension which allowed me to define them in one go

1 Answers

You could use a type family, and type-level lists-of-types.

{-# LANGUAGE TypeFamilies, DataKinds, TypeOperators #-}

import Data.Kind

type family ShowN (xs :: [*]) :: Constraint
type instance ShowN '[] = ()
type instance ShowN (t ': ts) = (Show t, ShowN ts)

foo :: ShowN '[a, b, c] => a -> b -> c -> String
foo xa xb xc = show xa ++ " " ++ show xb ++ " " ++ show xc

main :: IO ()
main = putStrLn (foo 3 True 'f')
Related