实例声明中的副作用

时间:2019-04-29 15:38:21

标签: haskell types default monads side-effects

说我想为UTCTime创建一个包装器:

data CustomDateStamp = CustomDateStamp
    { 
      stampValue :: UTCTime
    } deriving (Show, Eq, Ord, Typeable)

现在说我想为此设置一个默认值,例如“现在”。

instance Default CustomDateStamp where
    def = CustomDateStamp getCurrentTime def

(显然)此操作失败,并显示:

   • Couldn't match expected type ‘UTCTime’
                  with actual type ‘IO UTCTime’
    • In the first argument of ‘CustomDateStamp’, namely ‘getCurrentTime’
      In the expression: CustomDateStamp getCurrentTime def
      In an equation for ‘def’: def = CustomDateStamp getCurrentTime def
    |
98  |     def = CustomDateStamp getCurrentTime def
    |                   ^^^^^^^^^^^^^^

我的问题是,如何在实例定义中使用副作用操作?这有可能吗?这种情况下首选的方法是什么?

3 个答案:

答案 0 :(得分:4)

首先,您不能这样做。一旦进入IO,就始终处于IO中(并且Default已经有一个IO a实例无法执行您想要的操作)。制定不同的计划。

答案 1 :(得分:2)

我想把这种情况写成默认值需要IO操作的类型

instance {-# OVERLAPPING #-} Default (IO CustomDateStamp) where
    def = CustomDateStamp <$> getCurrentTime

(可轻松调整,例如用于mtl-stack)。有点争议,因为重叠是顽皮的。

编辑:需要OVERLAPPINGIO CustomDateStampIO a更具体,因此在范围内应选择此实例。

答案 2 :(得分:0)

getCurrentTime :: IO UTCTime起,您不能仅仅称呼它。没有类型为IO a -> a

的函数

除了unsafePerformIO(以及其他类似的魔术东西)。我强烈劝阻你不要走那条路。