3

这个问题与我关于班级的其他问题有关。当我尝试以以下自然方式定义类的实例时(@tel 对上述问题的回答向我建议),我得到编译器错误:smallCheckTest.SmallCheck.SeriesSerial

data Person = SnowWhite | Dwarf Int
instance Serial Person where ...

事实证明,Serial想要有两个论点。反过来,这需要一些编译器标志。以下作品:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
import Test.SmallCheck
import Test.SmallCheck.Series
import Control.Monad.Identity

data Person = SnowWhite | Dwarf Int

instance Serial Identity Person where
        series = generate (\d -> SnowWhite : take (d-1) (map Dwarf [1..7]))

我的问题是:

  1. 把它放在Identity那里是“正确的做法”吗?我受到Test.Series.list函数类型的启发(当我第一次看到它时我也觉得非常奇怪):

    list :: Depth -> Series Identity a -> [a]
    

    什么是正确的做法?Identity每次看到就盲目的放进去会好吗?我应该放一些类似的东西Serial m Integer => Serial m Person(这需要一些看起来更可怕的编译器标志:FlexibleContexts至少UndecidableInstances)?

  2. 第一个参数(min Serial m n)是做什么用的?

    谢谢!

4

1 回答 1

4

我只是 smallcheck 的用户而不是开发人员,但我认为答案是

1)不是真的。你应该让它保持多态,你可以在没有上述扩展的情况下做到这一点:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}
import Test.SmallCheck
import Test.SmallCheck.Series
import Control.Monad.Identity

data Person = SnowWhite | Dwarf Int deriving (Show)

instance (Monad m) => Serial m Person where
        series = generate (\d -> SnowWhite : take (d-1) (map Dwarf [1..7]))

2)系列目前定义为

newtype Series m a = Series (ReaderT Depth (LogicT m) a)

这意味着这是用于生成系列中的值m的基本 monad 。LogicT例如,IO代替写入m将允许在生成系列时发生 IO 操作。

在 SmallCheck 中,m也出现在Testable实例声明中,例如instance (Serial m a, Show a, Testable m b) => Testable m (a->b). 这具有具体的效果,smallCheck :: Testable IO a => Depth -> a -> IO ()如果您只有Identity.

在实践中,您可以通过编写一个自定义驱动程序函数来利用这一事实,该函数将一些单子效应交错,例如在所述驱动程序中记录生成的值(或某些此类)。

它也可能对我不知道的其他事情有用。

于 2013-05-15T08:21:57.660 回答