假设我们有一个quickcheck属性,用于验证Functor
的实例是否满足身份法:
-- | A covariant functor.
class Map m where
(<@>) :: (a -> b) -> m a -> m b
data Proxy a = Proxy
-- | The functor identity law.
prop_mapIdentityLaw :: (Eq (m a), Show (m a), Map m)
=> Proxy (m a)
-> m a
-> Bool
prop_mapIdentityLaw _ x = (id <@> x) == id x
我想编写一个针对我创建的实例运行此属性的函数。大致类似于:
verify :: IO ()
verify =
mapM_ quickCheck [ prop_mapIdentityLaw t | t <- types ]
where
types =
[ Proxy :: Proxy (Id Int) ]
如果我要将另一个代理添加到我的类型列表中(例如Proxy :: Proxy (Option Int)
),显然这不起作用,因为Proxy
的类型为Proxy (Id Int)
。
几年前我使用过很多Haskell,但我不熟悉一些较新的扩展。我想知道是否有办法通过RankNTypes
和DataKinds
或其他一些扩展组合实现这一目标。
答案 0 :(得分:2)
您需要以存在类型打包相关词典(实例的见证人),以便使“类型列表”成为同类词:
-- Carries a Proxy with a bunch of dictionaries
data ProxyA where
ProxyA :: (Eq (m a), Show (m a), Map m, Arbitrary (m a)) => Proxy (m a) -> ProxyA
-- | The functor identity law.
prop_mapIdentityLaw :: (Eq (m a), Show (m a), Map m)
=> Proxy (m a)
-> m a
-> Bool
prop_mapIdentityLaw _ x = (id <@> x) == id x
verify :: IO ()
verify = forM_ types $ \ (ProxyA p) -> quickCheck $ prop_mapIdentityLaw p
where
types :: [ ProxyA ]
types =
[ ProxyA (Proxy :: Proxy (Id Int))
, ProxyA (Proxy :: Proxy (Id Char))
]
请注意,由于存在类型的工作原理,您无法在[ prop_mapIdentityLaw p | ProxyA p <- types ]
中列出部分应用程序,因为此列表不是同类的。如果您在顶部添加quickCheck
,那么它就会变得同质。