haskellghcderivingderivingvia

Wrap a type in newtype


In the following code I got warning Orphan instance: instance (MonadIO m, Monad m) => GenerateUUID m

instance (MonadIO m, Monad m) => GenerateUUID m where
  generateUUID = liftIO nextRandom

According to it the solution is either

        move the instance declaration to the module of the class or of the type, or
        wrap the type with a newtype and declare the instance on the new type.

(or disable the warning hat Internet also suggest)

My problem is that I'm not able to find how to wrap the type with a newtype?


Solution

  • You can define a newtype wrapper like this:

    newtype Foo m a = Foo { unFoo :: m a }
    

    If we also want to say "I want Foo to have the same instances for Functor, Monad, Applicative... that m has, the only difference being that the methods use Foo m a instead of m a" we can use the -XDerivingVia extension:

    {-# LANGUAGE DerivingVia #-}
    
    newtype Foo m a = Foo { unFoo :: m a } 
                    deriving (Functor,Applicative,Monad,MonadIO,GenerateUUID) via m
    

    Any time the compiler complains about a missing instance for Foo, add it to the deriving clause.


    A slight refinement. Suppose we also wanted to "inherit" Semigroup and Monoid instances. For example: IO () is a Monoid, so we might want Foo IO () to be a Monoid as well. We need a separate deriving clause:

    newtype Foo m a = Foo { unFoo :: m a } 
                    deriving (Functor,Applicative,Monad,MonadIO) via m
                    deriving (Semigroup,Monoid) via (m a)
    

    Why a separate clause? Because the typeclasses have different kinds. Functor has kind (Type -> Type) -> Constraint and we are declaring the instance for Foo m, which has kind Type -> Type.

    Meanwhile, Semigroup has kind Type -> Constraint and we are declaring the instance for Foo m a, the "fully applied" type constructor with kind Type.