用 newtype 包装一个类型
Wrap a type in newtype
在下面的代码中我得到了警告 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.
(或者禁用警告帽网上也有建议)
我的问题是我找不到如何用新类型包装类型?
您可以像这样定义一个新类型包装器:
newtype Foo m a = Foo { unFoo :: m a }
如果我们还想说 "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
" 我们可以使用 -XDerivingVia
扩展名:
{-# LANGUAGE DerivingVia #-}
newtype Foo m a = Foo { unFoo :: m a }
deriving (Functor,Applicative,Monad,MonadIO,GenerateUUID) via m
任何时候编译器抱怨缺少 Foo
的实例,将其添加到 deriving
子句。
略微改进。假设我们还想 "inherit" Semigroup
和 Monoid
实例。例如:IO ()
是 Monoid
,所以我们可能希望 Foo IO ()
也是 Monoid
。我们需要一个单独的 deriving
子句:
newtype Foo m a = Foo { unFoo :: m a }
deriving (Functor,Applicative,Monad,MonadIO) via m
deriving (Semigroup,Monoid) via (m a)
为什么要有一个单独的子句?因为类型类有不同的种类。 Functor
有种类 (Type -> Type) -> Constraint
,我们正在为 Foo m
声明实例,它有种类 Type -> Type
.
与此同时,Semigroup
具有种类 Type -> Constraint
,我们正在为 Foo m a
声明实例,"fully applied" 类型构造函数具有种类 Type
。
在下面的代码中我得到了警告 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.
(或者禁用警告帽网上也有建议)
我的问题是我找不到如何用新类型包装类型?
您可以像这样定义一个新类型包装器:
newtype Foo m a = Foo { unFoo :: m a }
如果我们还想说 "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
" 我们可以使用 -XDerivingVia
扩展名:
{-# LANGUAGE DerivingVia #-}
newtype Foo m a = Foo { unFoo :: m a }
deriving (Functor,Applicative,Monad,MonadIO,GenerateUUID) via m
任何时候编译器抱怨缺少 Foo
的实例,将其添加到 deriving
子句。
略微改进。假设我们还想 "inherit" Semigroup
和 Monoid
实例。例如:IO ()
是 Monoid
,所以我们可能希望 Foo IO ()
也是 Monoid
。我们需要一个单独的 deriving
子句:
newtype Foo m a = Foo { unFoo :: m a }
deriving (Functor,Applicative,Monad,MonadIO) via m
deriving (Semigroup,Monoid) via (m a)
为什么要有一个单独的子句?因为类型类有不同的种类。 Functor
有种类 (Type -> Type) -> Constraint
,我们正在为 Foo m
声明实例,它有种类 Type -> Type
.
与此同时,Semigroup
具有种类 Type -> Constraint
,我们正在为 Foo m a
声明实例,"fully applied" 类型构造函数具有种类 Type
。