I made a way to get more free stuff and free stuff is good.
The current implementation of deriveVia
is here, it works with all the examples here. Needs GHC 8.2 and th-desugar.
for new Haskellers to get pampered by their compiler. For the price of a line or two the compiler offers to do your job, to write uninteresting code for you (in the form of type classes) such as equality, comparison, serialization, ... in the case of 3-D vectors
-- Eq :: Type -> Constraint
-- Ord :: Type -> Constraint
-- Show :: Type -> Constraint
-- Read :: Type -> Constraint
data V3 a = V3 a a a
deriving (Eq, Ord, Show, Read, ...)
In the distant past GHC could only be cajoled into defining a few classes hard-coded into the compiler. With time that list grew to include more interesting classes — type classes over type constructors (of kind Type -> Type
) rather than simple types (Type
) — but always at the discretion of compiler writers.
{-# Language DeriveTraversable #-}
-- Functor :: (Type -> Type) -> Constraint
-- Foldable :: (Type -> Type) -> Constraint
-- Traversable :: (Type -> Type) -> Constraint
data V3 a = V3 a a a
deriving (..., Functor, Foldable, Traversable)
With the advent of default methods and Generic
the rubber band was on the other claw, library writers could now specify a generic, singular (privileged) function to be the default implementation of certain methods.
The JSON-library aeson provides default implementations of JSON serialization
class ToJSON a where
toJSON :: a -> Value
toJSON = genericToJSON defaultOptions
default
toJSON :: (Generic a, GToJSON Value Zero (Rep a)) => a -> Value
class FromJSON a where
parseJSON :: Value -> Parser a
parseJSON = genericParseJSON defaultOptions
default
parseJSON :: (Generic a, GFromJSON Zero (Rep a)) => Value -> Parser a
so users don't even have to specify them
{-# Language DeriveGeneric #-}
import GHC.Generics (Generic)
import Data.Aeson (ToJSON, FromJSON)
data V3 a = V3 a a a
deriving
(..., Generic)
instance ToJSON a => ToJSON (V3 a)
instance FromJSON a => FromJSON (V3 a)
Then we got the option of deriving any class like this
{-# Language ..., DeriveAnyClass #-}
data V3 a = V3 a a a
deriving
(..., Generic, ToJSON, FromJSON)
and with the latest release (GHC 8.2) we get the option to be more explicit
{-# Language ..., DerivingStrategies #-}
data V3 a = V3 a a a
deriving
(Eq, Ord, Show, Read, Generic)
deriving
(Functor, Foldable, Traversable)
deriving anyclass
(ToJSON, FromJSON)
There are many more applications, some allow us to avoid boilerplate code and others allow us to codify ‘common Haskell knowledge’ (like getting
Num
fromApplicative
).Another example of such knowledge is that
Monad
can be defined in terms of aFunctor
withreturn
andjoin
:so given an instance for
MonadJoin
we can deriveMonad
viaWrappedMonadJoin
Sometimes
join
is more intuitive, we may also wish to specifyApplicative
in terms of the equivalentMonoidal
usingWrappedMonoidal
It also allows us to work with crazy hierarchies like this where we can derive everything..