From 34264aceedf3b44fb54a80232b511abec9800453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baldur=20Bl=C3=B6ndal?= Date: Wed, 23 Mar 2022 21:22:21 +0000 Subject: [PATCH 1/2] Binary instance for Generically. --- README.md | 36 +++++++++++++++++++++++++++--------- changelog.md | 6 ++++++ src/Data/Binary.hs | 33 +++++++++++++++++++++++---------- src/Data/Binary/Class.hs | 13 +++++++++++++ 4 files changed, 69 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 73bc9a55..0b2fa9ad 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The ``binary`` package provides Data.Binary, containing the Binary class, and associated methods, for serialising values to and from lazy -ByteStrings. +ByteStrings. A key feature of ``binary`` is that the interface is both pure, and efficient. The ``binary`` package is portable to GHC and Hugs. @@ -54,23 +54,41 @@ the ``Get`` and ``Put`` monads. More information in the haddock documentation. -## Deriving binary instances using GHC's Generic ## +## Deriving binary instances, ``Generically`` ## -Beginning with GHC 7.2, it is possible to use binary serialization without -writing any instance boilerplate code. +Beginning with GHC 9.4 it is possible to derive binary serialization +using the ``Generically`` newtype. + +This is achieved by deriving an instance of ``Generic`` and then +deriving the appropriate ``Binary T`` instance via ``Generically T``. ```haskell -{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DerivingStrategies #-} +{-# LANGUAGE DerivingVia #-} import Data.Binary -import GHC.Generics (Generic) +import GHC.Generics (Generic, Generically(..)) + +data Foo = Foo + deriving stock Generic + deriving Binary via Generically Foo +``` -data Foo = Foo deriving (Generic) +Beginning with GHC 7.2 this generic definition has been a part of the +``Binary`` typeclass. This could also be derived using the +``anyclass`` strategy: --- GHC will automatically fill out the instance -instance Binary Foo +```haskell +data Foo = Foo + deriving stock Generic + deriving anyclass Binary ``` +Which means the same as an empty class declaration: ``instance +Binary Foo``. + ## Contributors ## * Lennart Kolmodin diff --git a/changelog.md b/changelog.md index 96ea33bd..8626eb94 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,12 @@ binary binary-0.8.9.0 -------------- +- Add binary instance for 'GHC.Generics.Generically'. `Binary T` can + be derived via `Generically T` for a suitable generic type `T`. + +binary-0.8.9.0 +-------------- + - Compatibility with GHC 9.2 - Drop instances for deprecated `Data.Semigroup.Option` diff --git a/src/Data/Binary.hs b/src/Data/Binary.hs index 07970a3e..4e964f6c 100644 --- a/src/Data/Binary.hs +++ b/src/Data/Binary.hs @@ -230,19 +230,32 @@ decodeFileOrFail f = ------------------------------------------------------------------------ -- $generics -- --- Beginning with GHC 7.2, it is possible to use binary serialization --- without writing any instance boilerplate code. +-- Beginning with GHC 9.4 it is possible to derive binary +-- serialization using the 'GHC.Generics.Generically' newtype. -- --- > {-# LANGUAGE DeriveGeneric #-} +-- This is achieved by deriving an instance of 'GHC.Generics.Generic' +-- and then deriving the appropriate @'Binary' T@ instance via +-- @Generically T@. +-- +-- > {-# LANGUAGE DeriveAnyClass #-} +-- > {-# LANGUAGE DeriveGeneric #-} +-- > {-# LANGUAGE DerivingStrategies #-} +-- > {-# LANGUAGE DerivingVia #-} -- > -- > import Data.Binary --- > import GHC.Generics (Generic) +-- > import GHC.Generics (Generic, Generically(..)) -- > -- > data Foo = Foo --- > deriving (Generic) --- > --- > -- GHC will automatically fill out the instance --- > instance Binary Foo +-- > deriving stock Generic +-- > deriving Binary via Generically Foo -- --- This mechanism makes use of GHC's efficient built-in generics --- support. +-- Beginning with GHC 7.2 this generic definition has been a part of +-- the 'Binary' typeclass. This could also be derived using the +-- @anyclass@ strategy: +-- +-- > data Foo = Foo +-- > deriving stock Generic +-- > deriving anyclass Binary +-- +-- Which means the same as an empty class declaration: @instance +-- Binary Foo@. diff --git a/src/Data/Binary/Class.hs b/src/Data/Binary/Class.hs index 895f43ba..21bf6545 100644 --- a/src/Data/Binary/Class.hs +++ b/src/Data/Binary/Class.hs @@ -13,6 +13,10 @@ #define HAS_TYPELITS_CHAR #endif +#if MIN_VERSION_base(4,17,0) +#define HAS_GENERICALLY +#endif + #if MIN_VERSION_base(4,8,0) #define HAS_NATURAL #define HAS_VOID @@ -175,6 +179,15 @@ class Binary t where defaultPutList :: Binary a => [a] -> Put defaultPutList xs = put (length xs) <> mapM_ put xs +#ifdef HAS_GENERICALLY +instance (Generic a, GBinaryPut (Rep a), GBinaryGet (Rep a)) => Binary (Generically a) where + put :: Generically a -> Put + put (Generically a) = gput (from a) + + get :: Get (Generically a) + get = Generically . to <$> gget +#endif + ------------------------------------------------------------------------ -- Simple instances From f7d6f13add742dac7c6dd166491b6f174797c616 Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 6 Mar 2023 17:13:14 -0500 Subject: [PATCH 2/2] Update changelog.md --- changelog.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/changelog.md b/changelog.md index a2f3e50e..6703e00d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,16 +1,17 @@ binary ====== -binary-0.8.9.1 + +binary-0.8.9.2 -------------- -- Fix redundant pattern match warning in GHC 9.4 +- Add binary instance for `GHC.Generics.Generically`. `Binary T` can + be derived via `Generically T` for a suitable generic type `T`. -binary-0.8.9.0 +binary-0.8.9.1 -------------- -- Add binary instance for 'GHC.Generics.Generically'. `Binary T` can - be derived via `Generically T` for a suitable generic type `T`. +- Fix redundant pattern match warning in GHC 9.4 binary-0.8.9.0 --------------