import qualified Control.Monad data D c a b = D (c a b) (c b a) apply :: (c a b -> c a2 b2) -> (c b a -> c b2 a2) -> D c a b -> D c a2 b2 apply f1 f2 (D x y) = D (f1 x) (f2 y) applyBoth = Control.Monad.join apply f :: Int -> String f = show g :: String -> Int g = read h :: Int -> Int h = (*2) join :: (a -> b) -> (c -> d) -> ((a, c) -> (b, d)) join f g (x, y) = (f x, g y) x1 = D f g f1 = join h y1 = apply f1 f1 x1 -- This compiles y2 = apply g g x1 where g = f1 -- Also works z1 = applyBoth f1 x1 -- This fails main = return ()