{-# LANGUAGE DataKinds #-} {-# LANGUAGE TypeFamilies #-} data Nullable a = X a type family AllowAssign a b where AllowAssign (Nullable a) (Nullable b) = 'True AllowAssign (Nullable a) b = 'False AllowAssign a b = 'True assign :: AllowAssign a b ~ 'True => a -> b -> IO () assign _ _ = return () main :: IO () main = do assign (X ()) (X ()) -- assign (X ()) () -- uncommenting this yields a type error assign () (X ()) assign () () putStrLn "yay"