0

在下面的代码中,我收到了警告Orphan instance: instance (MonadIO m, Monad m) => GenerateUUID m

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

根据它,解决方案是

        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.

(或禁用警告帽子互联网也建议)

我的问题是我无法找到如何用新类型包装类型?

4

1 回答 1

2

您可以像这样定义一个新类型包装器:

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

如果我们还想说“我想FooFunctor, Monad, Applicative...m拥有相同的实例,唯一的区别是方法使用Foo m a而不是m a”,我们可以使用-XDerivingVia扩展名:

{-# LANGUAGE DerivingVia #-}

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

每当编译器抱怨缺少 的实例时Foo,将其添加到deriving子句中。


稍作细化。假设我们还想“继承”SemigroupMonoid实例。例如:IO ()is a Monoid,所以我们可能也想Foo IO ()成为 a Monoid。我们需要一个单独的deriving子句:

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

为什么要单独的条款?因为类型类有不同的种类。Functor有 kind (Type -> Type) -> Constraint,我们正在声明具有 kind 的Foo m实例Type -> Type

同时,Semigroup有 kind Type -> Constraint,我们正在声明一个实例Foo m a,用 kind 声明“完全应用”的类型构造函数Type

于 2020-06-13T09:09:02.147 回答