我有以下类型类(省略了不相关的方法):
class Initializable a where
initialize :: IO a
initialize = return initializePure
{# convenience method for implementations, not to be called from outside #}
initializePure :: a
data Foo = Foo
instance Initializable Foo where
initializePure = Foo
data Bar = Bar
instance Initializable Bar where
initialize = initializeBar
有些实现需要IO
来初始化自己,有些则不需要。
此代码发出警告:
No explicit implementation for
‘initializePure’
In the instance declaration for ‘Initializable Bar’
我试图像这样添加MINIMAL
pragma:
{-# MINIMAL initializePure | initialize #-}
但后来我收到了另一个警告:
The MINIMAL pragma does not require:
‘initializePure’
but there is no default implementation.
In the class declaration for ‘Initializable’
我的目的是通过提供 {/ 1>} Initializable
或initialize
来initializePure
,但仅在定义之外使用initialize
。
如何干净地编译代码?
答案 0 :(得分:5)
编译器警告这一点非常正确,因为不能可以在只能用IO初始化的类型上使用initialisePure
。
使这种安全的唯一方法是将这两种情况分开;最简单的可能性是两个类:
class Initialisable a where
initialise :: IO a
class Initialisable a => PureInitialisable a where
initialisePure :: a
data Foo = Foo
instance Initialisable Foo where
initialise = return Foo
instance PureInitialisable Foo where
initialisePure = Foo
data Bar = Bar
initialiseBar :: IO Bar
initialiseBar = undefined
instance Initialisable Bar where
initialise = initialiseBar
您无法为PureInitialisable
提供默认实施,因为某些类型的不存在,例如Bar
。但是,如果您启用DefaultSignatures
,则可以为Initialisable
提供默认值,以便在类型恰好为PureInitialisable
时启动:
{-# LANGUAGE DefaultSignatures #-}
class Initialisable a where
initialise :: IO a
default initialise :: PureInitialisable a => IO a
initialise = return initialisePure
对于像Foo
这样的类型,这可以让你写
instance PureInitialisable Foo where initialisePure = Foo
instance Initialisable Foo
略短。
另一种方法可能是使初始化可以自定义的monad:
{-# LANGUAGE TypeFamilies #-}
class Initialisable a where
type InitialisationM a :: *
type InitialisationM a = a
initialise :: InitialisationM a
instance Initialisable Foo where
initialise = Foo
instance Initialisable Bar where
type InitialisationM Bar = IO Bar
initialise = initialiseBar