【问题标题】:Making an Arbitrary Instance for a newtype that uses Maybe为使用 Maybe 的新类型创建任意实例
【发布时间】:2016-10-17 15:01:59
【问题描述】:

我想为以下新类型创建一个Arbitrary 实例,以便将其用于快速检查:

newtype Wrapmaybe a = Wrapmaybe {getMaybe :: Maybe a} deriving (Eq, Show)

我知道MaybeArbitrary实例可以写成如下:

instance Arbitrary a => Arbitrary (Maybe a) where
     arbitrary = frequency [(1, return Nothing), (1, liftM Just arbitrary)]

我如何编写Arbitrary 实例以用于以下内容,而不会出现类型错误或类型错误:

instance Arbitrary a => Arbitrary (Wrapmaybe Maybe a) where
   etc...

【问题讨论】:

  • 要写这样一个实例,你必须改变Wrapmaybe的定义——也许你正在寻找newtype Wrap f a = Wrap (f a)

标签: haskell quickcheck


【解决方案1】:

好吧,您可以将该实例中的每个 Maybe 构造函数替换为您的新类型的相应构造函数:

instance Arbitrary a => Arbitrary (WrapMaybe a) where
  arbitrary = frequency [ (1, return $ WrapMaybe Nothing)
                        , (1, fmap (WrapMaybe . Just) arbitrary) ]

但是,使用已经存在的Maybe 实例,只需对结果执行一次就更简单了:

instance Arbitrary a => Arbitrary (WrapMaybe a) where
  arbitrary = fmap WrapMaybe arbitrary

你也可以写WrapMaybe <$> arbitrary。但请不要使用liftM,即obsolete! (这些都是等价的。)

【讨论】:

  • ...或打开GeneralizedNewtypeDeriving 并将Arbitrary 添加到派生实例列表中。
  • liftM 并不比ap 过时。 liftM 用于编写 Functor 实例,ap 用于编写 Applicative 实例。然而,其他用途确实已经过时了。
  • @dfeuer:除非没有充分的理由定义fmap = liftM。通常,Functor 实例可以只派生(与 Applicative 不同),否则自己定义 fmap 通常非常简单——而且通常该实例比单子派生的实例更通用或更有效. OTOH,<*> = ap 非常方便,因为实现<*>>>= 的难度相似,因此您只需担心后者即可节省大量工作。
  • 非常有帮助的答案!看到多种可能性是非常有用的。非常感谢您的帮助:)
  • 对于某些 monads(尤其是那些基于连续传递的):ap 比直接实现 <*> 慢很多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多