这个问题与我关于smallCheck
的Test.SmallCheck.Series
类的另一个问题有关。当我尝试以以下自然方式定义类Serial
的实例时(由@tel对上述问题的回答建议),我得到编译器错误:
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]))
我的问题是:
是否将
Identity
放在那里"正确的事情要做"?我受到Test.Series.list
函数类型的启发(当我第一次看到它时,我也发现它非常奇怪):list :: Depth -> Series Identity a -> [a]
正确的做法是什么?如果我只是盲目地把
Identity
在我看到它的时候?我应该把Serial m Integer => Serial m Person
之类的东西代替(这需要一些更可怕的编译器标志:FlexibleContexts
和UndecidableInstances
至少)?第一个参数(
Serial m n
中的m
)是什么?谢谢!
我只是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
是用于生成序列中的值的LogicT
的基单子。例如,用IO
代替m
将允许在生成序列时发生IO操作。
在SmallCheck中,m
也出现在Testable
实例声明中,如instance (Serial m a, Show a, Testable m b) => Testable m (a->b)
。如果您只有Identity
的实例,则无法使用诸如smallCheck :: Testable IO a => Depth -> a -> IO ()
之类的先前存在的驱动程序函数。