2018-07-20 17:07:24 +03:00
{- # LANGUAGE DefaultSignatures, TypeOperators, UndecidableInstances # -}
2018-07-19 21:45:04 +03:00
module Data.Mergeable ( Mergeable ( .. ) ) where
2016-07-23 00:38:10 +03:00
2017-07-28 21:37:02 +03:00
import Control.Applicative
2016-07-26 10:56:10 +03:00
import Data.Functor.Identity
2017-09-26 02:49:20 +03:00
import Data.List.NonEmpty
2018-05-02 19:00:15 +03:00
import Data.Sum
2018-07-20 16:54:57 +03:00
import qualified Data.Syntax as Syntax
import qualified Data.Syntax.Comment as Comment
import qualified Data.Syntax.Declaration as Declaration
import qualified Data.Syntax.Statement as Statement
2016-07-23 00:38:10 +03:00
import GHC.Generics
-- Classes
2016-07-26 22:35:28 +03:00
-- | A 'Mergeable' functor is one which supports pushing itself through an 'Alternative' functor. Note the similarities with 'Traversable' & 'Crosswalk'.
--
-- This is a kind of distributive law which produces (at least) the union of the two functors’ shapes; i.e. unlike 'Traversable', an 'empty' value in the inner functor does not produce an 'empty' result, and unlike 'Crosswalk', an 'empty' value in the outer functor does not produce an 'empty' result.
2016-07-27 06:32:48 +03:00
--
2018-04-09 23:50:08 +03:00
-- For example, 'Data.Diff' uses 'sequenceAlt' to select one side or the other of a diff node, while correctly handling the fact that some patches don’ t have any content for that side.
2016-07-23 00:38:10 +03:00
class Functor t => Mergeable t where
2018-04-09 23:50:08 +03:00
-- | Sequence a 'Mergeable' functor by merging the 'Alternative' values.
2016-07-23 00:38:10 +03:00
sequenceAlt :: Alternative f => t ( f a ) -> f ( t a )
2018-04-09 23:26:49 +03:00
default sequenceAlt :: ( Generic1 t , GMergeable ( Rep1 t ) , Alternative f ) => t ( f a ) -> f ( t a )
sequenceAlt = genericSequenceAlt
2016-07-23 00:38:10 +03:00
-- Instances
2017-09-26 02:49:20 +03:00
instance Mergeable [] where
2018-04-09 23:35:33 +03:00
sequenceAlt = foldr ( \ x -> ( ( ( : ) <$> x <|> pure id ) <*> ) ) ( pure [] )
2017-09-26 02:49:20 +03:00
instance Mergeable NonEmpty where
2018-04-09 23:35:33 +03:00
sequenceAlt ( x :| [] ) = ( :| ) <$> x <*> pure []
sequenceAlt ( x1 :| x2 : xs ) = ( :| ) <$> x1 <*> sequenceAlt ( x2 : xs ) <|> sequenceAlt ( x2 :| xs )
2017-09-26 02:49:20 +03:00
instance Mergeable Maybe where
2018-04-09 23:35:33 +03:00
sequenceAlt = maybe ( pure empty ) ( fmap Just )
instance Mergeable Identity where
sequenceAlt = fmap Identity . runIdentity
2017-09-26 02:25:21 +03:00
2018-05-02 19:00:15 +03:00
instance ( Apply Functor fs , Apply Mergeable fs ) => Mergeable ( Sum fs ) where
2018-05-29 15:53:37 +03:00
sequenceAlt = apply' @ Mergeable ( \ reinj t -> reinj <$> sequenceAlt t )
2017-09-26 02:44:00 +03:00
2018-07-20 17:07:53 +03:00
instance Mergeable Comment . Comment
instance Mergeable Declaration . Function
instance Mergeable Declaration . Method
instance Mergeable Statement . If
instance Mergeable Syntax . Context
instance Mergeable Syntax . Empty
instance Mergeable Syntax . Identifier
2017-09-26 02:44:00 +03:00
-- Generics
class GMergeable t where
2018-04-09 23:26:49 +03:00
gsequenceAlt :: Alternative f => t ( f a ) -> f ( t a )
2017-09-26 02:44:00 +03:00
2018-04-09 23:26:49 +03:00
genericSequenceAlt :: ( Generic1 t , GMergeable ( Rep1 t ) , Alternative f ) => t ( f a ) -> f ( t a )
genericSequenceAlt = fmap to1 . gsequenceAlt . from1
2017-09-26 02:44:00 +03:00
-- Instances
instance GMergeable U1 where
2018-04-09 23:26:49 +03:00
gsequenceAlt _ = pure U1
2017-09-26 02:44:00 +03:00
instance GMergeable Par1 where
2018-04-09 23:26:49 +03:00
gsequenceAlt ( Par1 a ) = Par1 <$> a
2017-09-26 02:44:00 +03:00
instance GMergeable ( K1 i c ) where
2018-04-09 23:26:49 +03:00
gsequenceAlt ( K1 a ) = pure ( K1 a )
2017-09-26 02:44:00 +03:00
2017-09-26 02:49:20 +03:00
instance Mergeable f => GMergeable ( Rec1 f ) where
2018-04-09 23:26:49 +03:00
gsequenceAlt ( Rec1 a ) = Rec1 <$> sequenceAlt a
2017-09-26 02:44:00 +03:00
instance GMergeable f => GMergeable ( M1 i c f ) where
2018-04-09 23:26:49 +03:00
gsequenceAlt ( M1 a ) = M1 <$> gsequenceAlt a
2017-09-26 02:44:00 +03:00
instance ( GMergeable f , GMergeable g ) => GMergeable ( f :+: g ) where
2018-04-09 23:26:49 +03:00
gsequenceAlt ( L1 a ) = L1 <$> gsequenceAlt a
gsequenceAlt ( R1 a ) = R1 <$> gsequenceAlt a
2017-09-26 02:44:00 +03:00
instance ( GMergeable f , GMergeable g ) => GMergeable ( f :*: g ) where
2018-04-09 23:26:49 +03:00
gsequenceAlt ( a :*: b ) = ( :*: ) <$> gsequenceAlt a <*> gsequenceAlt b