1
1
mirror of https://github.com/github/semantic.git synced 2024-12-28 09:21:35 +03:00

🔥 Data.Adjoined.

This commit is contained in:
Rob Rix 2016-04-14 21:59:11 -04:00
parent 8fc7a094a5
commit e4e3418a7a
2 changed files with 0 additions and 69 deletions

View File

@ -18,7 +18,6 @@ library
, Category
, Control.Comonad.Cofree
, Control.Monad.Free
, Data.Adjoined
, Data.Align
, Data.Bifunctor.These
, Data.Coalescent

View File

@ -1,68 +0,0 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Data.Adjoined where
import Control.Applicative
import Control.Monad
import Data.Align
import Data.Bifunctor.These
import Data.Coalescent
import Data.Sequence as Seq hiding (null)
-- | A collection of elements which can be adjoined onto other such collections associatively. There are two big wins with Data.Adjoined:
-- |
-- | 1. Efficient adjoining of lines and concatenation, thanks to its use of Data.Sequences `Seq` type.
-- | 2. The Monoid instance guarantees that adjoining cannot touch any lines other than the outermost.
-- |
-- | Since aligning diffs proceeds through the diff tree depth-first, adjoining child nodes and context from right to left, the former is crucial for efficiency, and the latter is crucial for correctness. Prior to using Data.Adjoined, repeatedly adjoining the last line in a node into its parent, and then its grandparent, and so forth, would sometimes cause blank lines to “travel” downwards, ultimately shifting blank lines at the end of nodes down proportionately to the depth in the tree at which they were introduced.
newtype Adjoined a = Adjoined { unAdjoined :: Seq a }
deriving (Eq, Foldable, Functor, Show, Traversable)
-- | Construct an Adjoined from a list.
fromList :: [a] -> Adjoined a
fromList = Adjoined . Seq.fromList
-- | Construct Adjoined by adding an element at the left.
cons :: a -> Adjoined a -> Adjoined a
cons a (Adjoined as) = Adjoined (a <| as)
-- | Destructure a non-empty Adjoined into Just the leftmost element and the rightward remainder of the Adjoined, or Nothing otherwise.
uncons :: Adjoined a -> Maybe (a, Adjoined a)
uncons (Adjoined v) | a :< as <- viewl v = Just (a, Adjoined as)
| otherwise = Nothing
-- | Construct Adjoined by adding an element at the right.
snoc :: Adjoined a -> a -> Adjoined a
snoc (Adjoined as) a = Adjoined (as |> a)
-- | Destructure a non-empty Adjoined into Just the rightmost element and the leftward remainder of the Adjoined, or Nothing otherwise.
unsnoc :: Adjoined a -> Maybe (Adjoined a, a)
unsnoc (Adjoined v) | as :> a <- viewr v = Just (Adjoined as, a)
| otherwise = Nothing
instance Applicative Adjoined where
pure = return
(<*>) = ap
instance Alternative Adjoined where
empty = Adjoined Seq.empty
Adjoined a <|> Adjoined b = Adjoined (a >< b)
instance Monad Adjoined where
return = Adjoined . return
a >>= f | Just (a, as) <- uncons a = f a <|> (as >>= f)
| otherwise = Adjoined Seq.empty
instance Coalescent a => Monoid (Adjoined a) where
mempty = Adjoined Seq.empty
a `mappend` b | Just (as, a) <- unsnoc a,
Just (b, bs) <- uncons b
= as <|> coalesce a b <|> bs
| otherwise = Adjoined (unAdjoined a >< unAdjoined b)
instance Align Adjoined where
nil = Adjoined Seq.empty
align as bs | Just (as, a) <- unsnoc as,
Just (bs, b) <- unsnoc bs = align as bs `snoc` These a b
| null bs = This <$> as
| null as = That <$> bs
| otherwise = nil