I noticed that the test suite for Data.Set
only really defines Arbitrary Set a
sensibly for a ~ Int
, but to avoid the GHC special ~
it uses
instance Enum a => Arbitrary (Set a)
How can I make sure only the Arbitrary (Set Int)
instance is used without needing any GHC extensions? In GHC-only code, I'd use either FlexibleInstances
or GADTs
and then either
instance Arbitrary (Set Int)
or
instance a ~ Int => Arbitrary (Set a)
A typeclass defines a set of methods that is shared across multiple types. For a type to belong to a typeclass, it needs to implement the methods of that typeclass. These implementations are ad-hoc: methods can have different implementations for different types.
Deriving means that your data type is automatically able to "derive" instances for certain type classes. In this case BaseballPlayer derives Show which means we can use any function that requires an instance of Show to work with BaseballPlayer .
This is possible using an idea I think I first encountered in a paper by Oleg Kiselyov, and which underlies Control.Lens.Equality
.
import Data.Functor.Identity
class IsInt a where
fromIntF :: f Int -> f a
instance IsInt Int where
fromIntF fx = fx
toIntF :: IsInt a => g a -> g Int
toIntF = unf . fromIntF . F $ id
newtype F g a b = F {unf :: g b -> a}
fromInt :: IsInt a => Int -> a
fromInt = runIdentity . fromIntF . Identity
toInt :: IsInt a => a -> Int
toInt = runIdentity . toIntF . Identity
Now I can use
instance IsInt a => Arbitrary (Set a)
and be confident that I'm really dealing with Int
. For convenience, I can constrain the IsInt
class with any classes I need of which Int
is an instance:
class (Show a, Read a, Integral a, Arbitrary a) => IsInt a where ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With