{-# LANGUAGE GADTs #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE RankNTypes #-} import GHC.Exts (Constraint) class Function f where type Constraints f a :: Constraint type instance Constraints f a = () type Result f a type instance Result f a = a applyFunc :: (Constraints f a) => f -> a -> Result f a pairmap :: (Function f, Constraints f a, Constraints f b) => f -> (a, b) -> (Result f a, Result f b) pairmap f (x,y) = (applyFunc f x, applyFunc f y) data NumFunc where NumFunc :: (forall a. Num a => a -> a) -> NumFunc instance Function NumFunc where type Constraints NumFunc a = (Num a) applyFunc (NumFunc f) = f data EnumFunc where EnumFunc :: (forall a. Enum a => a -> a) -> EnumFunc instance Function EnumFunc where type Constraints EnumFunc a = (Enum a) applyFunc (EnumFunc f) = f data MaybeFunc where MaybeFunc :: (forall a. a -> Maybe a) -> MaybeFunc instance Function MaybeFunc where type Result MaybeFunc a = Maybe a applyFunc (MaybeFunc f) = f y1 = pairmap (NumFunc (+2)) (1::Int, 2::Float) y2 = pairmap (EnumFunc succ) (1::Int, 'a') y3 = pairmap (MaybeFunc Just) ('a', True) main = do print y1 print y2 print y3