{-# language GADTs #-} data C = C data A1 = A1 data A2 = A2 fa :: A1 -> Maybe A2 -> C fa = undefined data B1 = B1 data B2 = B2 fb :: B1 -> Maybe B2 -> C fb = undefined data Sum1 = InA1 A1 | InB1 B1 data Sum2 = InA2 A2 | InB2 B2 data Tag a where TagA :: Tag A2 TagB :: Tag B2 test :: Sum1 -> Maybe Sum2 -> Either String C test sum1 sum2 = case sum1 of InA1 a -> g TagA $ fa a InB1 b -> g TagB $ fb b where g :: Tag a -> (Maybe a -> C) -> Either String C g tag f = case sum2 of Nothing -> Right $ f Nothing Just x -> case (tag, x) of (TagA, InA2 a) -> Right $ f (Just a) (TagB, InB2 b) -> Right $ f (Just b) _ -> Left "..." main = undefined