From 0b2b27ff218f08178536cdb41136e1dffe8619b4 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 16:40:56 -0400 Subject: [PATCH 01/17] Stub in an AppMerge semigroup. --- semantic.cabal | 1 + src/Data/Semigroup/App.hs | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/Data/Semigroup/App.hs diff --git a/semantic.cabal b/semantic.cabal index 132722e06..9b8c4b9af 100644 --- a/semantic.cabal +++ b/semantic.cabal @@ -72,6 +72,7 @@ library , Data.Patch , Data.Range , Data.Record + , Data.Semigroup.App , Data.Source , Data.Span , Data.SplitDiff diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs new file mode 100644 index 000000000..7f183d5eb --- /dev/null +++ b/src/Data/Semigroup/App.hs @@ -0,0 +1,7 @@ +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +module Data.Semigroup.App where + +import Control.Applicative + +newtype AppMerge f a = AppMerge { runAppMerge :: f a } + deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) From 541e23043148cc626c15de951c6eb16c80b60eb7 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 16:41:32 -0400 Subject: [PATCH 02/17] Define a Semigroup instance for AppMerge. --- src/Data/Semigroup/App.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 7f183d5eb..07d5c0ec0 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -2,6 +2,10 @@ module Data.Semigroup.App where import Control.Applicative +import Data.Semigroup newtype AppMerge f a = AppMerge { runAppMerge :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) + +instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where + AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b) From 794a03a49c124887ff3b3a172386d76688fda05b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 16:41:41 -0400 Subject: [PATCH 03/17] :memo: AppMerge. --- src/Data/Semigroup/App.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 07d5c0ec0..9b393f126 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -4,6 +4,7 @@ module Data.Semigroup.App where import Control.Applicative import Data.Semigroup +-- | 'Semigroup' under '<*>' and '<>'. newtype AppMerge f a = AppMerge { runAppMerge :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) From 88230df1fe910acd5c7cf4840313b488413f90b5 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 16:41:49 -0400 Subject: [PATCH 04/17] Define a Monoid instance for AppMerge. --- src/Data/Semigroup/App.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 9b393f126..639c1c87c 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -10,3 +10,7 @@ newtype AppMerge f a = AppMerge { runAppMerge :: f a } instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b) + +instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where + mempty = AppMerge (pure mempty) + mappend = (<>) From 8f22cb26f885e9a302a0233de71cc5bea62cc724 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 16:44:35 -0400 Subject: [PATCH 05/17] Explicitly list the exports. --- src/Data/Semigroup/App.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 639c1c87c..875d3319d 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -1,5 +1,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} -module Data.Semigroup.App where +module Data.Semigroup.App +( AppMerge(..) +) where import Control.Applicative import Data.Semigroup From 6399cb3c58a3d0963b58331f266e2d36c7a452d8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:07:49 -0400 Subject: [PATCH 06/17] Define an App semigroup. --- src/Data/Semigroup/App.hs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 875d3319d..6fec42eb1 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -1,6 +1,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Data.Semigroup.App ( AppMerge(..) +, App(..) ) where import Control.Applicative @@ -16,3 +17,7 @@ instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where mempty = AppMerge (pure mempty) mappend = (<>) + + +newtype App f a = App { runApp :: f a } + deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) From 5ea6482e96571f026780686f0c7d1068f3460ea1 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:07:55 -0400 Subject: [PATCH 07/17] :memo: App. --- src/Data/Semigroup/App.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 6fec42eb1..4708edb27 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -19,5 +19,6 @@ instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where mappend = (<>) +-- | 'Semigroup' under '*>'. newtype App f a = App { runApp :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) From 3329bd0a5176ca5d17f39b9e39497368895d6ddd Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:08:06 -0400 Subject: [PATCH 08/17] Define a Semigroup instance for App. --- src/Data/Semigroup/App.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 4708edb27..4218a110c 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -22,3 +22,6 @@ instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where -- | 'Semigroup' under '*>'. newtype App f a = App { runApp :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) + +instance Applicative f => Semigroup (App f a) where + App a <> App b = App (a *> b) From e0245ed7524cbfbbb0021769a2642d037ced7680 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:08:14 -0400 Subject: [PATCH 09/17] Define a Monoid instance for App. --- src/Data/Semigroup/App.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 4218a110c..414ce1c9b 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -25,3 +25,7 @@ newtype App f a = App { runApp :: f a } instance Applicative f => Semigroup (App f a) where App a <> App b = App (a *> b) + +instance (Applicative f, Monoid a) => Monoid (App f a) where + mempty = App (pure mempty) + mappend = (<>) From 256623a81816f02703d336d246febe8fd50a8f90 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:08:25 -0400 Subject: [PATCH 10/17] eval lists in App. --- src/Data/Abstract/Evaluatable.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index adf41de29..21d7c6a98 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -16,6 +16,7 @@ import Data.Abstract.Value import Data.Functor.Classes import Data.Proxy import Data.Semigroup.Foldable +import Data.Semigroup.App import Data.Term import Prelude hiding (fail) import Prologue @@ -51,7 +52,7 @@ instance Evaluatable s => Evaluatable (TermF s a) where -- 3. Only the last statement’s return value is returned. instance Evaluatable [] where -- 'nonEmpty' and 'foldMap1' enable us to return the last statement’s result instead of 'unit' for non-empty lists. - eval = maybe unit (runImperative . foldMap1 (Imperative . subtermValue)) . nonEmpty + eval = maybe unit (runApp . foldMap1 (App . subtermValue)) . nonEmpty -- | A 'Semigroup' providing an imperative context which extends the local environment with new bindings. newtype Imperative m a = Imperative { runImperative :: m a } From 69a4e4cc2eff281725274f3bff8018e0bb8e9fa8 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:08:52 -0400 Subject: [PATCH 11/17] :fire: Imperative. --- src/Data/Abstract/Evaluatable.hs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Data/Abstract/Evaluatable.hs b/src/Data/Abstract/Evaluatable.hs index 21d7c6a98..c4cb0ff63 100644 --- a/src/Data/Abstract/Evaluatable.hs +++ b/src/Data/Abstract/Evaluatable.hs @@ -53,13 +53,3 @@ instance Evaluatable s => Evaluatable (TermF s a) where instance Evaluatable [] where -- 'nonEmpty' and 'foldMap1' enable us to return the last statement’s result instead of 'unit' for non-empty lists. eval = maybe unit (runApp . foldMap1 (App . subtermValue)) . nonEmpty - --- | A 'Semigroup' providing an imperative context which extends the local environment with new bindings. -newtype Imperative m a = Imperative { runImperative :: m a } - -instance MonadEnvironment value m => Semigroup (Imperative m a) where - Imperative a <> Imperative b = Imperative (a *> b) - -instance (MonadEnvironment value m, MonadValue value m) => Monoid (Imperative m value) where - mempty = Imperative unit - mappend = (<>) From c6148c6cad3f5322ab5a6bcc54f6319fb1815859 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:16:09 -0400 Subject: [PATCH 12/17] Test the associativity of the semigroup instances. --- src/Data/Semigroup/App.hs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 414ce1c9b..78922f68c 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -7,10 +7,17 @@ module Data.Semigroup.App import Control.Applicative import Data.Semigroup +-- $setup +-- >>> import Test.QuickCheck +-- >>> instance Arbitrary (f a) => Arbitrary (App f a) where arbitrary = App <$> arbitrary +-- >>> instance Arbitrary (f a) => Arbitrary (AppMerge f a) where arbitrary = AppMerge <$> arbitrary + -- | 'Semigroup' under '<*>' and '<>'. newtype AppMerge f a = AppMerge { runAppMerge :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) +-- $ Associativity: +-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: AppMerge Maybe String) instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b) @@ -23,6 +30,8 @@ instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where newtype App f a = App { runApp :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) +-- $ Associativity: +-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: App Maybe Integer) instance Applicative f => Semigroup (App f a) where App a <> App b = App (a *> b) From 6be056bd9ad6ac5fdce2b38754932d77a2b43255 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:16:31 -0400 Subject: [PATCH 13/17] Swap the order of the types. --- src/Data/Semigroup/App.hs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 78922f68c..8292024e7 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -1,7 +1,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} module Data.Semigroup.App -( AppMerge(..) -, App(..) +( App(..) +, AppMerge(..) ) where import Control.Applicative @@ -12,20 +12,6 @@ import Data.Semigroup -- >>> instance Arbitrary (f a) => Arbitrary (App f a) where arbitrary = App <$> arbitrary -- >>> instance Arbitrary (f a) => Arbitrary (AppMerge f a) where arbitrary = AppMerge <$> arbitrary --- | 'Semigroup' under '<*>' and '<>'. -newtype AppMerge f a = AppMerge { runAppMerge :: f a } - deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) - --- $ Associativity: --- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: AppMerge Maybe String) -instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where - AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b) - -instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where - mempty = AppMerge (pure mempty) - mappend = (<>) - - -- | 'Semigroup' under '*>'. newtype App f a = App { runApp :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) @@ -38,3 +24,17 @@ instance Applicative f => Semigroup (App f a) where instance (Applicative f, Monoid a) => Monoid (App f a) where mempty = App (pure mempty) mappend = (<>) + + +-- | 'Semigroup' under '<*>' and '<>'. +newtype AppMerge f a = AppMerge { runAppMerge :: f a } + deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable) + +-- $ Associativity: +-- prop> \ a b c -> a <> (b <> c) == (a <> b) <> (c :: AppMerge Maybe String) +instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where + AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b) + +instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where + mempty = AppMerge (pure mempty) + mappend = (<>) From b55010c2c1e5339bd311287a28dd10ec329a98a7 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:22:34 -0400 Subject: [PATCH 14/17] Define shrinking. --- src/Data/Semigroup/App.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 8292024e7..506fafe80 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -9,8 +9,8 @@ import Data.Semigroup -- $setup -- >>> import Test.QuickCheck --- >>> instance Arbitrary (f a) => Arbitrary (App f a) where arbitrary = App <$> arbitrary --- >>> instance Arbitrary (f a) => Arbitrary (AppMerge f a) where arbitrary = AppMerge <$> arbitrary +-- >>> instance Arbitrary (f a) => Arbitrary (App f a) where arbitrary = App <$> arbitrary ; shrink = map App . shrink . runApp +-- >>> instance Arbitrary (f a) => Arbitrary (AppMerge f a) where arbitrary = AppMerge <$> arbitrary ; shrink = map AppMerge . shrink . runAppMerge -- | 'Semigroup' under '*>'. newtype App f a = App { runApp :: f a } From aab509cf63ea1d858e39b64f75f00c79a2a2c6f2 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:26:07 -0400 Subject: [PATCH 15/17] Test the identity properties. --- src/Data/Semigroup/App.hs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 506fafe80..ccd10f4f5 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -21,6 +21,9 @@ newtype App f a = App { runApp :: f a } instance Applicative f => Semigroup (App f a) where App a <> App b = App (a *> b) +-- $ Identity: +-- prop> \ a -> mempty <> a == (a :: App Maybe String) +-- prop> \ a -> a <> mempty == (a :: App Maybe String) instance (Applicative f, Monoid a) => Monoid (App f a) where mempty = App (pure mempty) mappend = (<>) @@ -35,6 +38,9 @@ newtype AppMerge f a = AppMerge { runAppMerge :: f a } instance (Applicative f, Semigroup a) => Semigroup (AppMerge f a) where AppMerge a <> AppMerge b = AppMerge ((<>) <$> a <*> b) +-- $ Identity: +-- prop> \ a -> mempty <> a == (a :: AppMerge Maybe String) +-- prop> \ a -> a <> mempty == (a :: AppMerge Maybe String) instance (Applicative f, Monoid a, Semigroup a) => Monoid (AppMerge f a) where mempty = AppMerge (pure mempty) mappend = (<>) From 6a785e0b30beb64d8feda6666f54a36c7816b8d4 Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:26:32 -0400 Subject: [PATCH 16/17] =?UTF-8?q?Remove=20the=20Monoid=20instance=20for=20?= =?UTF-8?q?App,=20as=20it=E2=80=99s=20unlawful.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Data/Semigroup/App.hs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index ccd10f4f5..58d666076 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -21,13 +21,6 @@ newtype App f a = App { runApp :: f a } instance Applicative f => Semigroup (App f a) where App a <> App b = App (a *> b) --- $ Identity: --- prop> \ a -> mempty <> a == (a :: App Maybe String) --- prop> \ a -> a <> mempty == (a :: App Maybe String) -instance (Applicative f, Monoid a) => Monoid (App f a) where - mempty = App (pure mempty) - mappend = (<>) - -- | 'Semigroup' under '<*>' and '<>'. newtype AppMerge f a = AppMerge { runAppMerge :: f a } From d645481dcfd182b2d3fbd5d68359087d3bd4838b Mon Sep 17 00:00:00 2001 From: Rob Rix Date: Wed, 21 Mar 2018 17:29:48 -0400 Subject: [PATCH 17/17] :memo: AppMerge is a Monoid too. --- src/Data/Semigroup/App.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Semigroup/App.hs b/src/Data/Semigroup/App.hs index 58d666076..4ed13ff3c 100644 --- a/src/Data/Semigroup/App.hs +++ b/src/Data/Semigroup/App.hs @@ -22,7 +22,7 @@ instance Applicative f => Semigroup (App f a) where App a <> App b = App (a *> b) --- | 'Semigroup' under '<*>' and '<>'. +-- | 'Semigroup' and 'Monoid' under '<*>' and '<>'. newtype AppMerge f a = AppMerge { runAppMerge :: f a } deriving (Alternative, Applicative, Bounded, Enum, Eq, Foldable, Functor, Monad, Ord, Show, Traversable)