1
1
mirror of https://github.com/github/semantic.git synced 2024-12-18 12:21:57 +03:00
semantic/test/Data/Mergeable.hs

87 lines
3.2 KiB
Haskell
Raw Normal View History

2019-10-30 20:16:17 +03:00
{-# LANGUAGE DefaultSignatures, FlexibleContexts, TypeApplications, TypeOperators, UndecidableInstances #-}
module Data.Mergeable ( Mergeable (..) ) where
2016-07-23 00:38:10 +03:00
2017-07-28 21:37:02 +03:00
import Control.Applicative
import Data.Functor.Identity
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.
--
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 dont 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
instance Mergeable [] where
sequenceAlt = foldr (\ x -> (((:) <$> x <|> pure id) <*>)) (pure [])
instance Mergeable NonEmpty where
sequenceAlt (x :|[]) = (:|) <$> x <*> pure []
sequenceAlt (x1:|x2:xs) = (:|) <$> x1 <*> sequenceAlt (x2 : xs) <|> sequenceAlt (x2:|xs)
instance Mergeable Maybe where
sequenceAlt = maybe (pure empty) (fmap Just)
instance Mergeable Identity where
sequenceAlt = fmap Identity . runIdentity
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)
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
-- Generics
class GMergeable t where
2018-04-09 23:26:49 +03:00
gsequenceAlt :: Alternative f => t (f a) -> f (t a)
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
-- Instances
instance GMergeable U1 where
2018-04-09 23:26:49 +03:00
gsequenceAlt _ = pure U1
instance GMergeable Par1 where
2018-04-09 23:26:49 +03:00
gsequenceAlt (Par1 a) = Par1 <$> a
instance GMergeable (K1 i c) where
2018-04-09 23:26:49 +03:00
gsequenceAlt (K1 a) = pure (K1 a)
instance Mergeable f => GMergeable (Rec1 f) where
2018-04-09 23:26:49 +03:00
gsequenceAlt (Rec1 a) = Rec1 <$> sequenceAlt a
instance GMergeable f => GMergeable (M1 i c f) where
2018-04-09 23:26:49 +03:00
gsequenceAlt (M1 a) = M1 <$> gsequenceAlt a
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
instance (GMergeable f, GMergeable g) => GMergeable (f :*: g) where
2018-04-09 23:26:49 +03:00
gsequenceAlt (a :*: b) = (:*:) <$> gsequenceAlt a <*> gsequenceAlt b