packages feed

verifiable-expressions (empty) → 0.4.0

raw patch · 19 files changed

+3083/−0 lines, 19 filesdep +basedep +containersdep +lenssetup-changed

Dependencies added: base, containers, lens, mtl, sbv, transformers, union, vinyl

Files

+ LICENSE view
@@ -0,0 +1,202 @@++                                 Apache License+                           Version 2.0, January 2004+                        http://www.apache.org/licenses/++   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION++   1. Definitions.++      "License" shall mean the terms and conditions for use, reproduction,+      and distribution as defined by Sections 1 through 9 of this document.++      "Licensor" shall mean the copyright owner or entity authorized by+      the copyright owner that is granting the License.++      "Legal Entity" shall mean the union of the acting entity and all+      other entities that control, are controlled by, or are under common+      control with that entity. For the purposes of this definition,+      "control" means (i) the power, direct or indirect, to cause the+      direction or management of such entity, whether by contract or+      otherwise, or (ii) ownership of fifty percent (50%) or more of the+      outstanding shares, or (iii) beneficial ownership of such entity.++      "You" (or "Your") shall mean an individual or Legal Entity+      exercising permissions granted by this License.++      "Source" form shall mean the preferred form for making modifications,+      including but not limited to software source code, documentation+      source, and configuration files.++      "Object" form shall mean any form resulting from mechanical+      transformation or translation of a Source form, including but+      not limited to compiled object code, generated documentation,+      and conversions to other media types.++      "Work" shall mean the work of authorship, whether in Source or+      Object form, made available under the License, as indicated by a+      copyright notice that is included in or attached to the work+      (an example is provided in the Appendix below).++      "Derivative Works" shall mean any work, whether in Source or Object+      form, that is based on (or derived from) the Work and for which the+      editorial revisions, annotations, elaborations, or other modifications+      represent, as a whole, an original work of authorship. For the purposes+      of this License, Derivative Works shall not include works that remain+      separable from, or merely link (or bind by name) to the interfaces of,+      the Work and Derivative Works thereof.++      "Contribution" shall mean any work of authorship, including+      the original version of the Work and any modifications or additions+      to that Work or Derivative Works thereof, that is intentionally+      submitted to Licensor for inclusion in the Work by the copyright owner+      or by an individual or Legal Entity authorized to submit on behalf of+      the copyright owner. For the purposes of this definition, "submitted"+      means any form of electronic, verbal, or written communication sent+      to the Licensor or its representatives, including but not limited to+      communication on electronic mailing lists, source code control systems,+      and issue tracking systems that are managed by, or on behalf of, the+      Licensor for the purpose of discussing and improving the Work, but+      excluding communication that is conspicuously marked or otherwise+      designated in writing by the copyright owner as "Not a Contribution."++      "Contributor" shall mean Licensor and any individual or Legal Entity+      on behalf of whom a Contribution has been received by Licensor and+      subsequently incorporated within the Work.++   2. Grant of Copyright License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      copyright license to reproduce, prepare Derivative Works of,+      publicly display, publicly perform, sublicense, and distribute the+      Work and such Derivative Works in Source or Object form.++   3. Grant of Patent License. Subject to the terms and conditions of+      this License, each Contributor hereby grants to You a perpetual,+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable+      (except as stated in this section) patent license to make, have made,+      use, offer to sell, sell, import, and otherwise transfer the Work,+      where such license applies only to those patent claims licensable+      by such Contributor that are necessarily infringed by their+      Contribution(s) alone or by combination of their Contribution(s)+      with the Work to which such Contribution(s) was submitted. If You+      institute patent litigation against any entity (including a+      cross-claim or counterclaim in a lawsuit) alleging that the Work+      or a Contribution incorporated within the Work constitutes direct+      or contributory patent infringement, then any patent licenses+      granted to You under this License for that Work shall terminate+      as of the date such litigation is filed.++   4. Redistribution. You may reproduce and distribute copies of the+      Work or Derivative Works thereof in any medium, with or without+      modifications, and in Source or Object form, provided that You+      meet the following conditions:++      (a) You must give any other recipients of the Work or+          Derivative Works a copy of this License; and++      (b) You must cause any modified files to carry prominent notices+          stating that You changed the files; and++      (c) You must retain, in the Source form of any Derivative Works+          that You distribute, all copyright, patent, trademark, and+          attribution notices from the Source form of the Work,+          excluding those notices that do not pertain to any part of+          the Derivative Works; and++      (d) If the Work includes a "NOTICE" text file as part of its+          distribution, then any Derivative Works that You distribute must+          include a readable copy of the attribution notices contained+          within such NOTICE file, excluding those notices that do not+          pertain to any part of the Derivative Works, in at least one+          of the following places: within a NOTICE text file distributed+          as part of the Derivative Works; within the Source form or+          documentation, if provided along with the Derivative Works; or,+          within a display generated by the Derivative Works, if and+          wherever such third-party notices normally appear. The contents+          of the NOTICE file are for informational purposes only and+          do not modify the License. You may add Your own attribution+          notices within Derivative Works that You distribute, alongside+          or as an addendum to the NOTICE text from the Work, provided+          that such additional attribution notices cannot be construed+          as modifying the License.++      You may add Your own copyright statement to Your modifications and+      may provide additional or different license terms and conditions+      for use, reproduction, or distribution of Your modifications, or+      for any such Derivative Works as a whole, provided Your use,+      reproduction, and distribution of the Work otherwise complies with+      the conditions stated in this License.++   5. Submission of Contributions. Unless You explicitly state otherwise,+      any Contribution intentionally submitted for inclusion in the Work+      by You to the Licensor shall be under the terms and conditions of+      this License, without any additional terms or conditions.+      Notwithstanding the above, nothing herein shall supersede or modify+      the terms of any separate license agreement you may have executed+      with Licensor regarding such Contributions.++   6. Trademarks. This License does not grant permission to use the trade+      names, trademarks, service marks, or product names of the Licensor,+      except as required for reasonable and customary use in describing the+      origin of the Work and reproducing the content of the NOTICE file.++   7. Disclaimer of Warranty. Unless required by applicable law or+      agreed to in writing, Licensor provides the Work (and each+      Contributor provides its Contributions) on an "AS IS" BASIS,+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or+      implied, including, without limitation, any warranties or conditions+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A+      PARTICULAR PURPOSE. You are solely responsible for determining the+      appropriateness of using or redistributing the Work and assume any+      risks associated with Your exercise of permissions under this License.++   8. Limitation of Liability. In no event and under no legal theory,+      whether in tort (including negligence), contract, or otherwise,+      unless required by applicable law (such as deliberate and grossly+      negligent acts) or agreed to in writing, shall any Contributor be+      liable to You for damages, including any direct, indirect, special,+      incidental, or consequential damages of any character arising as a+      result of this License or out of the use or inability to use the+      Work (including but not limited to damages for loss of goodwill,+      work stoppage, computer failure or malfunction, or any and all+      other commercial damages or losses), even if such Contributor+      has been advised of the possibility of such damages.++   9. Accepting Warranty or Additional Liability. While redistributing+      the Work or Derivative Works thereof, You may choose to offer,+      and charge a fee for, acceptance of support, warranty, indemnity,+      or other liability obligations and/or rights consistent with this+      License. However, in accepting such obligations, You may act only+      on Your own behalf and on Your sole responsibility, not on behalf+      of any other Contributor, and only if You agree to indemnify,+      defend, and hold each Contributor harmless for any liability+      incurred by, or claims asserted against, such Contributor by reason+      of your accepting any such warranty or additional liability.++   END OF TERMS AND CONDITIONS++   APPENDIX: How to apply the Apache License to your work.++      To apply the Apache License to your work, attach the following+      boilerplate notice, with the fields enclosed by brackets "[]"+      replaced with your own identifying information. (Don't include+      the brackets!)  The text should be enclosed in the appropriate+      comment syntax for the file format. We also recommend that a+      file or class name and description of purpose be included on the+      same "printed page" as the copyright notice for easier+      identification within third-party archives.++   Copyright [yyyy] [name of copyright owner]++   Licensed under the Apache License, Version 2.0 (the "License");+   you may not use this file except in compliance with the License.+   You may obtain a copy of the License at++       http://www.apache.org/licenses/LICENSE-2.0++   Unless required by applicable law or agreed to in writing, software+   distributed under the License is distributed on an "AS IS" BASIS,+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+   See the License for the specific language governing permissions and+   limitations under the License.
+ Language/Expression.hs view
@@ -0,0 +1,529 @@+{-# LANGUAGE DefaultSignatures         #-}+{-# LANGUAGE DeriveDataTypeable        #-}+{-# LANGUAGE FlexibleContexts          #-}+{-# LANGUAGE FlexibleInstances         #-}+{-# LANGUAGE LambdaCase                #-}+{-# LANGUAGE MultiParamTypeClasses     #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE PolyKinds                 #-}+{-# LANGUAGE RankNTypes                #-}+{-# LANGUAGE StandaloneDeriving        #-}+{-# LANGUAGE UndecidableInstances      #-}++{-|+Implements higher-ranked equivalents of 'Functor', 'Monad', 'Foldable' and+'Traversable'.+-}+module Language.Expression where++import           Control.Applicative               (Alternative, (<|>))+import           Control.Monad                     ((<=<), (>=>))+import           Data.Monoid                       (Alt (..))+import           Data.Typeable                     (Typeable)++import           Control.Monad.Trans.Reader        (ReaderT (..))+import           Control.Monad.Trans.Except        (ExceptT (..))+import qualified Control.Monad.Trans.State.Lazy    as L+import qualified Control.Monad.Trans.State.Strict  as S+import qualified Control.Monad.Trans.Writer.Lazy   as L+import qualified Control.Monad.Trans.Writer.Strict as S++import           Data.Functor.Compose              (Compose (..))+import           Data.Functor.Const                (Const (..))+import           Data.Functor.Identity             (Identity (..))+import           Data.Functor.Product              (Product (..))+import           Data.Functor.Reverse              (Reverse (..))+import           Data.Functor.Sum                  (Sum (..))++infixr 1 ^>>=++--------------------------------------------------------------------------------+--  Functor / Monad+--------------------------------------------------------------------------------++{-|+Higher-ranked analogue of 'Functor'.+-}+class HFunctor (h :: (u -> *) -> u -> *) where+  {-|+  Higher-ranked analogue of 'fmap'. Has a default implementation in terms of+  'htraverse' for @'HTraversable' h@.+  -}+  hmap :: (forall b. t b -> t' b) -> h t a -> h t' a++  default hmap :: (HTraversable h) => (forall b. t b -> t' b) -> h t a -> h t' a+  hmap f = runIdentity . htraverse (Identity . f)++{-|+Half of the higher-ranked analogue of 'Monad'.+-}+class HPointed h where+  {-|+  Higher-ranked analogue of 'pure' or 'return'.+  -}+  hpure :: t a -> h t a++{-|+Half of the higher-ranked analogue of 'Monad'.+-}+class HBind h where+  {-|+  Higher-ranked analogue of '>>='.+  -}+  (^>>=) :: h t a -> (forall b. t b -> h t' b) -> h t' a++{-|++Higher-ranked analogue of 'Monad'.++NB there's no such thing as 'HApplicative' for a reason. Consider @f :: h t a ->+h t' a -> h ('Product' t t') a@, i.e. the higher-ranked analogue of @liftA2 (,)+:: f a -> f b -> f (a, b)@. Unfortunately @f@ can't exist, because @'Product'@+pairs up values /of the same type/, and in our constructions, @h@ potentially+contains values of many types; @a@ just happens to be the one at the top level.+There's no guarantee that the two structures will have the same types inside to+pair together.+-}+class (HFunctor h, HPointed h, HBind h) => HMonad h++{-|+Implements 'hmap' from just an 'HPointed' and 'HBind' instance. Can be used to+implement 'HFunctor' for your 'HMonad's that aren't 'HTraversable'.+-}+hliftM :: (HPointed h, HBind h) => (forall b. t b -> t' b) -> h t a -> h t' a+hliftM f x = x ^>>= hpure . f++{-|+Higher-ranked analogue of 'Control.Monad.join'.+-}+hjoin :: (HBind h) => h (h t) a -> h t a+hjoin x = x ^>>= id++--------------------------------------------------------------------------------+--  Traversable+--------------------------------------------------------------------------------++{-|+Higher-ranked analogue of 'Traversable'.+-}+class (HFunctor h) => HTraversable h where+  {-# MINIMAL htraverse | hsequence #-}++  {-|+  Higher-ranked analogue of 'traverse'.+  -}+  htraverse+    :: (Applicative f)+    => (forall b. t b -> f (t' b)) -> h t a -> f (h t' a)+  htraverse f = hsequence . hmap (Compose . f)++  {-|+  Higher-ranked analogue of 'sequenceA'.+  -}+  hsequence+    :: (Applicative f)+    => h (Compose f t) a -> f (h t a)+  hsequence = htraverse getCompose++-- | An 'HTraversable' instance lets you do something similar to 'foldMap'. For+-- a more flexible operation, see 'hfoldMap'.+hfoldMapMonoid+  :: (HTraversable h, Monoid m)+  => (forall b. t b -> m) -> h t a -> m+hfoldMapMonoid f = getConst . htraverse (Const . f)++hbindTraverse+  :: (HTraversable h, HMonad h, Applicative f)+  => (forall b. t b -> f (h t' b))+  -> h t a+  -> f (h t' a)+hbindTraverse f = fmap hjoin . htraverse f++--------------------------------------------------------------------------------+--  Binary Classes+--------------------------------------------------------------------------------++{-|+Higher-ranked analogue of 'Data.Bifunctor.Bifunctor'.+-}+class HBifunctor (h :: (k -> *) -> (k -> *) -> k -> *) where+  {-|+  Higher-ranked analogue of 'Data.Bifunctor.bimap'.+  -}+  hbimap :: (forall b. s b -> s' b)+         -> (forall b. t b -> t' b)+         -> h s t a+         -> h s' t' a+  hfirst :: (forall b. s b -> s' b) -> h s t a -> h s' t a+  hsecond :: (forall b. t b -> t' b) -> h s t a -> h s t' a++  default hbimap+    :: (HBitraversable h)+    => (forall b. s b -> s' b)+    -> (forall b. t b -> t' b)+    -> h s t a+    -> h s' t' a+  hbimap f g = runIdentity . hbitraverse (Identity . f) (Identity . g)++  hfirst f = hbimap f id+  hsecond = hbimap id++class (HBifunctor h) => HBitraversable h where+  hbitraverse+    :: (Applicative f)+    => (forall b. s b -> f (s' b))+    -> (forall b. t b -> f (t' b))+    -> h s t a -> f (h s' t' a)++hbifoldMapMonoid+  :: (Monoid m, HBitraversable h)+  => (forall b. s b -> m) -> (forall b. t b -> m) -> h s t a -> m+hbifoldMapMonoid f g = getConst . hbitraverse (Const . f) (Const . g)++--------------------------------------------------------------------------------+--  (Even) Higher-Ranked Binary Classes+--------------------------------------------------------------------------------++class HDuofunctor (h :: ((u -> *) -> u -> *) -> (u -> *) -> u -> *) where+  hduomap+    :: (forall g g' b. (forall c. g c -> g' c) -> s g b -> s' g' b)+    -> (forall b. t b -> t' b)+    -> h s t a+    -> h s' t' a++  default hduomap+    :: (HDuotraversable h)+    => (forall g g' b. (forall c. g c -> g' c) -> s g b -> s' g' b)+    -> (forall b. t b -> t' b)+    -> h s t a+    -> h s' t' a+  hduomap f g =+    runIdentity .+    hduotraverse (\h -> Identity . f (runIdentity . h)) (Identity . g)++hduomapFirst+  :: HDuofunctor h+  => (forall g g' b. (forall c. g c -> g' c) -> s g b -> s' g' b)+  -> h s t a+  -> h s' t a+hduomapFirst f = hduomap f id++hduomapFirst'+  :: (HDuofunctor h, HFunctor s)+  => (forall g b. s g b -> s' g b) -> h s t a -> h s' t a+hduomapFirst' f = hduomapFirst (\g -> f . hmap g)++hduomapSecond+  :: (HDuofunctor h, HFunctor s)+  => (forall b. t b -> t' b) -> h s t a -> h s t' a+hduomapSecond = hduomap hmap++class HDuofunctor h => HDuotraversable h where+  hduotraverse+    :: (Applicative f)+    => (forall g g' b. (forall c. g c -> f (g' c)) -> s g b -> f (s' g' b))+    -> (forall b. t b -> f (t' b))+    -> h s t a+    -> f (h s' t' a)++hduotraverseFirst+  :: (HDuotraversable h, Applicative f)+  => (forall g g' b. (forall c. g c -> f (g' c)) -> s g b -> f (s' g' b))+  -> h s t a+  -> f (h s' t a)+hduotraverseFirst f = hduotraverse f pure++hduotraverseFirst'+  :: (HDuotraversable h, HTraversable s, Monad f)+  => (forall g b. s g b -> f (s' g b)) -> h s t a -> f (h s' t a)+hduotraverseFirst' f = hduotraverseFirst (\g -> f <=< htraverse g)++hduotraverseSecond+  :: (HDuotraversable h, HTraversable s, Applicative f)+  => (forall b. t b -> f (t' b)) -> h s t a -> f (h s t' a)+hduotraverseSecond = hduotraverse htraverse++--------------------------------------------------------------------------------+--  Folding+--------------------------------------------------------------------------------++{-|+This is a more flexible, higher-ranked version of 'Foldable'. While 'Foldable'+only allows you to fold into a 'Monoid', 'HFoldable' allows you to fold into+some arbitrary type constructor @k@. This means that the instance can take+advantage of additional structure inside @k@ and @h@, to combine internal+results in different ways, rather than just the 'mappend' available to+'foldMap'.++Notice that if you have++@+instance ('Monoid' m) => 'HFoldableAt' ('Const' m) h+@++then 'hfoldMap' behaves very much like regular 'foldMap'.+-}+class HFoldableAt k h where+  hfoldMap :: (forall b. t b -> k b) -> h t a -> k a++{-|+For 'HFunctor's, provides an implementation of 'hfoldMap' in terms of a simple+'hfold'-like function.+-}+implHfoldMap+  :: (HFunctor h)+  => (h k a -> k a)+  -> (forall b. t b -> k b) -> h t a -> k a+implHfoldMap g f = g . hmap f++-- | A helper function for implementing instances with the general form @'Monad'+-- m => 'HFoldableAt' ('Compose' m t) h@. I.e. folding that requires a monadic+-- context of some kind.+implHfoldMapCompose+  :: (HTraversable h, Monad m)+  => (h k a -> m (k a))+  -> (forall b. t b -> Compose m k b) -> h t a -> Compose m k a+implHfoldMapCompose f = implHfoldMap (Compose . (htraverse getCompose >=> f))+++{-|+Higher-ranked equivalent of 'Data.Foldable.fold'.+-}+hfold :: HFoldableAt t h => h t a -> t a+hfold = hfoldMap id+++-- | Fold in an applicative context.+hfoldA :: (HFoldableAt (Compose f t) h, Applicative f) => h t a -> f (t a)+hfoldA = hfoldMapA pure+++-- | Fold in an applicative context.+hfoldMapA :: (HFoldableAt (Compose f k) h, Applicative f) => (forall b. t b -> f (k b)) -> h t a -> f (k a)+hfoldMapA f = getCompose . hfoldMap (Compose . f)+++-- | 'hfoldTraverse' is to 'hfoldMap' as 'htraverse' is to 'hmap'.+hfoldTraverse+  :: (HFoldableAt k h, HTraversable h, Applicative f)+  => (forall b. t b -> f (k b))+  -> h t a+  -> f (k a)+hfoldTraverse f = fmap hfold . htraverse f+++class HBifoldableAt k h where+  hbifoldMap :: (forall b. f b -> k b) -> (forall b. g b -> k b) -> h f g a -> k a++hbifold :: (HBifoldableAt k h) => h k k a -> k a+hbifold = hbifoldMap id id+++class HDuofoldableAt k h where+  hduofoldMap+    :: (HTraversable s)+    => (forall g b. (forall c. g c -> k c) -> s g b -> k b)+    -> (forall b. t b -> k b)+    -> h s t a+    -> k a+++implHduofoldMap+  :: (HDuofunctor h, HFunctor s)+  => ((forall g b. (forall c. g c -> k c) -> s g b -> k b) -> h s k a -> k a)+  -> (forall g b. (forall c. g c -> k c) -> s g b -> k b)+  -> (forall b. t b -> k b)+  -> h s t a+  -> k a+implHduofoldMap h f g = h f . hduomap hmap g+++implHduofoldMapCompose+  :: (HDuotraversable h, HTraversable s, Monad m)+  => ((forall g b. (forall c. g c -> m (k c)) -> s g b -> m (k b)) -> h s k a -> m (k a))+  -> (forall g b. (forall c. g c -> Compose m k c) -> s g b -> Compose m k b)+  -> (forall b. t b -> Compose m k b)+  -> h s t a+  -> Compose m k a+implHduofoldMapCompose f =+  implHduofoldMap+    (\g ->+       Compose .+       (hduotraverseSecond getCompose >=>+        f (\h -> getCompose . g (Compose . h))))++--------------------------------------------------------------------------------+--  Free Monads+--------------------------------------------------------------------------------++{-|+@'HFree' h@ is a higher-ranked free monad over the higher-ranked functor @h@.+That means that given @'HFunctor' h@, we get @'HMonad' ('HFree' h)@ for free.+-}+data HFree h t a+  = HPure (t a)+  | HWrap (h (HFree h t) a)+  deriving (Typeable)++instance HFunctor h => HFunctor (HFree h) where+  hmap = hliftM++instance HPointed (HFree h) where+  hpure = HPure++instance HFunctor h => HBind (HFree h) where+  HPure x ^>>= f = f x+  HWrap x ^>>= f = HWrap (hmap (^>>= f) x)++instance HFunctor h => HMonad (HFree h)+++instance (HFoldableAt k h) => HFoldableAt k (HFree h) where+  hfoldMap f = \case+    HPure x -> f x+    HWrap x -> hfoldMap (hfoldMap f) x+++instance HDuofoldableAt k HFree where+  hduofoldMap g f = \case+    HPure x -> f x+    HWrap x -> g (hduofoldMap g f) x+++instance HTraversable h => HTraversable (HFree h) where+  htraverse f = \case+    HPure x -> HPure <$> f x+    HWrap x -> HWrap <$> htraverse (htraverse f) x+++instance HDuofunctor HFree+instance HDuotraversable HFree where+  hduotraverse g f = \case+    HPure x -> HPure <$> f x+    HWrap x -> HWrap <$> g (hduotraverse g f) x++--------------------------------------------------------------------------------+--  Higher-ranked instances for standard functors+--------------------------------------------------------------------------------++--  'Compose' lifts a regular 'Functor'/'Monad'/etc into the higher-ranked+--  version++instance (Functor f) => HFunctor (Compose f) where+  hmap f = Compose . fmap f . getCompose++instance (Applicative f) => HPointed (Compose f) where+  hpure = Compose . pure++instance (Monad f) => HBind (Compose f) where+  Compose x ^>>= f = Compose (x >>= getCompose . f)++instance (Traversable f) => HTraversable (Compose f) where+  htraverse f = fmap Compose . traverse f . getCompose++-- | e.g. @('Monoid' m, 'Foldable' f) => 'HFoldableAt' ('Const' m) ('Compose' f)@+instance (Alternative g, Foldable f) => HFoldableAt g (Compose f) where+  hfoldMap f = getAlt . foldMap (Alt . f) . getCompose+++--------------------------------------------------------------------------------+-- 'Product'++instance HFunctor (Product f)+instance HTraversable (Product f) where+  htraverse f (Pair x y) = Pair x <$> f y++instance HBifunctor Product+instance HBitraversable Product where+  hbitraverse f g (Pair x y) = Pair <$> f x <*> g y++instance (Alternative k) => HBifoldableAt k Product where+  hbifoldMap f g (Pair x y) = f x <|> g y++instance (Alternative k) => HFoldableAt k (Product k) where+  hfoldMap = hbifoldMap id++--------------------------------------------------------------------------------+-- 'Reverse' (note there's nothing for the instances to reverse)++instance HFunctor Reverse+instance HTraversable Reverse where+  htraverse f (Reverse x) = Reverse <$> f x++instance HPointed Reverse where+  hpure = Reverse++instance HBind Reverse where+  Reverse x ^>>= f = f x++instance HMonad Reverse++instance HFoldableAt k Reverse where+  hfoldMap f (Reverse x) = f x++--------------------------------------------------------------------------------+-- 'Sum'++instance HFunctor (Sum f)+instance HTraversable (Sum f) where+  htraverse _ (InL x) = pure (InL x)+  htraverse f (InR y) = InR <$> f y++instance HBifunctor Sum+instance HBitraversable Sum where+  hbitraverse f _ (InL x) = InL <$> f x+  hbitraverse _ g (InR y) = InR <$> g y++instance HPointed (Sum f) where+  hpure = InR++instance HBind (Sum f) where+  InL x ^>>= _ = InL x+  InR y ^>>= f = f y++instance HMonad (Sum f)++instance HBifoldableAt k Sum where+  hbifoldMap f _ (InL x) = f x+  hbifoldMap _ g (InR y) = g y++instance HFoldableAt k (Sum k) where+  hfoldMap = hbifoldMap id++--------------------------------------------------------------------------------+-- 'StateT'++instance HFunctor (S.StateT s) where+  hmap f (S.StateT k) = S.StateT (f . k)++instance HFunctor (L.StateT s) where+  hmap f (L.StateT k) = L.StateT (f . k)++--------------------------------------------------------------------------------+-- 'WriterT'++instance HFunctor (S.WriterT w) where+  hmap f (S.WriterT x) = S.WriterT (f x)++instance HFunctor (L.WriterT w) where+  hmap f (L.WriterT x) = L.WriterT (f x)++--------------------------------------------------------------------------------+-- 'ReaderT'++instance HFunctor (ReaderT r) where+  hmap f (ReaderT k) = ReaderT (f . k)++instance HPointed (ReaderT r) where+  hpure = ReaderT . const++instance HBind (ReaderT r) where+  ReaderT k ^>>= f = ReaderT (\r -> runReaderT (f (k r)) r)++instance HMonad (ReaderT r)++--------------------------------------------------------------------------------+-- ExceptT++instance HFunctor (ExceptT e) where+  hmap f (ExceptT x) = ExceptT (f x)
+ Language/Expression/Choice.hs view
@@ -0,0 +1,228 @@+{-# LANGUAGE DataKinds                  #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE DeriveFunctor              #-}+{-# LANGUAGE DeriveTraversable          #-}+{-# LANGUAGE EmptyCase                  #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GADTs                      #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures             #-}+{-# LANGUAGE LambdaCase                 #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TemplateHaskell            #-}+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}+{-# LANGUAGE UndecidableInstances       #-}++module Language.Expression.Choice where+  -- (+  -- -- * Expressions+  --   HFree'(..)+  -- , _EVar'+  -- , _EOp'+  -- , squashExpression+  -- , eop'++  -- -- * HTraversable union+  -- , OpChoice(..)+  -- , ChooseOp(..)+  -- , SubsetOp(..)+  -- ) where++import           Data.Data++-- import           Data.Functor.Classes++import           Data.Union++import           Control.Lens         hiding (op)++import           Language.Expression++--------------------------------------------------------------------------------+--  Operator List Union+--------------------------------------------------------------------------------++-- | Form the union of a list of operators. This creates an operator which is a+-- choice from one of its constituents.+--+-- For example, @'OpChoice' '[NumOp, EqOp]@ is an operator that can either+-- represent an arithmetic operation or an equality comparison.+data OpChoice ops (t :: * -> *) a where+  OpThis :: op t a -> OpChoice (op : ops) t a+  OpThat :: OpChoice ops t a -> OpChoice (op : ops) t a+  deriving (Typeable)++_OpThis :: Prism' (OpChoice (op : ops) t a) (op t a)+_OpThis = prism' OpThis $ \case+  OpThis x -> Just x+  OpThat _ -> Nothing++_OpThat :: Prism' (OpChoice (op : ops) t a) (OpChoice ops t a)+_OpThat = prism' OpThat $ \case+  OpThis _ -> Nothing+  OpThat x -> Just x++noOps :: OpChoice '[] t a -> x+noOps = \case++instance HFunctor (OpChoice '[]) where+  hmap _ = noOps++instance HTraversable (OpChoice '[]) where+  htraverse _ = noOps++instance HFoldableAt k (OpChoice '[]) where+  hfoldMap _ = noOps++-- instance HEq (OpChoice '[]) where+--   liftHEq _ _ _ = noOps++instance (HFunctor op, HFunctor (OpChoice ops)) =>+  HFunctor (OpChoice (op : ops)) where++  hmap f = \case+    OpThis x -> OpThis (hmap f x)+    OpThat x -> OpThat (hmap f x)++instance (HTraversable op, HTraversable (OpChoice ops)) =>+  HTraversable (OpChoice (op : ops)) where++  htraverse f = \case+    OpThis x -> OpThis <$> htraverse f x+    OpThat x -> OpThat <$> htraverse f x++instance (HFoldableAt k op, HFoldableAt k (OpChoice ops)) =>+  HFoldableAt k (OpChoice (op : ops)) where++  hfoldMap f = \case+    OpThis x -> hfoldMap f x+    OpThat x -> hfoldMap f x++-- instance (HEq op, HEq (OpChoice ops)) =>+--   HEq (OpChoice (op : ops)) where++--   liftHEq le eq (OpThis x) (OpThis y) = liftHEq le eq x y+--   liftHEq le eq (OpThat x) (OpThat y) = liftHEq le eq x y+--   liftHEq _ _ _ _ = False+++-- instance (HEq (OpChoice ops), Eq1 t) => Eq1 (OpChoice ops t) where+--   liftEq = liftLiftEq+-- instance (Eq1 (OpChoice ops t), Eq a) => Eq (OpChoice ops t a) where+--   (==) = liftEq (==)+++newtype AsOp (t :: * -> *) a op = AsOp (op t a)++makeWrapped ''AsOp++choiceToUnion :: OpChoice ops t a -> Union (AsOp t a) ops+choiceToUnion = \case+  OpThis x -> This (AsOp x)+  OpThat x -> That (choiceToUnion x)++unionToChoice :: Union (AsOp t a) ops -> OpChoice ops t a+unionToChoice = \case+  This (AsOp x) -> OpThis x+  That x -> OpThat (unionToChoice x)++_OpChoice+  :: Iso (OpChoice ops t a) (OpChoice ops' t' a')+         (Union (AsOp t a) ops) (Union (AsOp t' a') ops')+_OpChoice = iso choiceToUnion unionToChoice+++-- | This class provides a low-boilerplate way of lifting individual operators+-- into a union, and extracting operators from a union.+class ChooseOp op ops where+  -- | Project a single operator from a union which contains it.+  chooseOp :: Prism' (OpChoice ops t a) (op t a)++instance UElem op ops i => ChooseOp op ops where+  chooseOp = _OpChoice . uprism . _Wrapped+++class SubsetOp ops1 ops2 where+  subsetOp :: Prism' (OpChoice ops2 t a) (OpChoice ops1 t a)++instance USubset ops1 ops2 is => SubsetOp ops1 ops2 where+  subsetOp = _OpChoice . usubset . from _OpChoice++--------------------------------------------------------------------------------+--  Expressions over a choice of operators+--------------------------------------------------------------------------------++-- | @'HFree'' ops v a@ is a higher-order free monad over the list of operators+-- @ops@ with variables in the type @v@ and it represents a value of type @a@.+--+-- Intuitively, it represents an expression which may contain operations from+-- any of the operators in the list @ops@.+newtype HFree' ops v a = HFree' { getHFree' :: HFree (OpChoice ops) v a }+  deriving (Typeable)++deriving instance+         (Data (HFree (OpChoice ops) v a), Typeable (HFree' ops v a)) =>+         Data (HFree' ops v a)++-- instance (HEq (OpChoice ops)) => HEq (HFree' ops) where+--   liftHEq le eq (HFree' x) (HFree' y) = liftHEq le eq x y++-- instance (Eq1 v, HEq (OpChoice ops)) => Eq1 (HFree' ops v) where+--   liftEq = liftLiftEq++-- instance (Eq1 v, HEq (OpChoice ops), Eq a) => Eq (HFree' ops v a) where+--   (==) = eq1+++-- TODO: Figure out type roles so these instances can be derived by+-- GeneralizedNewtypeDeriving++instance (HFunctor (OpChoice ops)) => HFunctor (HFree' ops) where+  hmap f = HFree' . hmap f . getHFree'++instance (HTraversable (OpChoice ops)) => HTraversable (HFree' ops) where+  htraverse f = fmap HFree' . htraverse f . getHFree'++instance HPointed (HFree' ops) where+  hpure = HFree' . hpure++instance (HFunctor (OpChoice ops)) => HBind (HFree' ops) where+  x ^>>= f = (HFree' . (^>>= (getHFree' . f)) . getHFree') x++instance (HFunctor (OpChoice ops)) => HMonad (HFree' ops) where++instance (HFoldableAt k (OpChoice ops), HFunctor (OpChoice ops)) =>+         HFoldableAt k (HFree' ops) where+  hfoldMap f (HFree' x) = hfoldMap f x++-- | Squash a composition of expressions over different operators into a+-- single-layered expression over a choice of the two operators.+squashExpression+  :: (HFunctor op1,+      HFunctor op2,+      HFunctor (OpChoice ops),+      ChooseOp op1 ops,+      ChooseOp op2 ops)+  => HFree op1 (HFree op2 v) a -> HFree' ops v a+squashExpression+  = HFree'+  . hjoin+  . hmap (hduomapFirst' (review chooseOp))+  . hduomapFirst' (review chooseOp)+  -- (review chooseOp)++hwrap'+  :: (HFunctor op, HFunctor (OpChoice ops), ChooseOp op ops)+  => op (HFree' ops v) a -> HFree' ops v a+hwrap' = HFree' . HWrap . review chooseOp . hmap getHFree'++--------------------------------------------------------------------------------+--  Lenses+--------------------------------------------------------------------------------++makeWrapped ''HFree'
+ Language/Expression/Example.hs view
@@ -0,0 +1,422 @@+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}++{-# OPTIONS_GHC -fno-warn-unused-imports #-}++{-|+"Language.Expression" provides a way of forming strongly types expression+languages from /operators/, via 'HFree'. This module is an explanation of how+that works, via a simple example.++This module is intended to be read via Haddock.+-}+module Language.Expression.Example where++import           Data.Functor.Identity (Identity (..))++import           Control.Monad.State++import           Data.Map              (Map)+import qualified Data.Map              as Map++import           Data.SBV              (EqSymbolic (..), OrdSymbolic (..),+                                        Predicate, SBV, Symbolic, isTheorem,+                                        ite, literal, symbolic)++import           Language.Expression++--------------------------------------------------------------------------------+-- * Operators++{-$+An /operator/ is a type constructor @op@ of kind @(* -> *) -> * -> *@. @op t+a@ should be seen as a way of combining @t@-objects which has a result type+@a@.++'SimpleOp' is an example of an operator type.+-}+++{-|+An operator type has two arguments. @t@ is a type constructor used to refer to+expressions. @a@ is the semantic type of the expression formed by the operator.+-}+data SimpleOp t a where+  -- | Given two int expressions, we may add them. Notice how we refer to expressions+  -- recursively with the type constructor parameter @t@.+  Add :: t Integer -> t Integer -> SimpleOp t Integer++  -- | Given two int expressions, we may compare them for equality. Notice the+  -- types of the arguments to the operator do not appear in the result type at+  -- all.+  Equal :: t Integer -> t Integer -> SimpleOp t Bool++  -- | Operator constructors can have any number of arguments, and you can mix+  -- argument types.+  IfThenElse :: t Bool -> t Integer -> t Integer -> SimpleOp t Integer++  -- | An operator does not have to actually combine expressions. It may produce an+  -- expression from a basic value, i.e. a literal int. 'HFree' itself does+  -- /not/ provide literals so they must be encoded in operators.+  Literal :: Integer -> SimpleOp t Integer++-- ** Type Classes++{-$+Most useful operators are instances of 'HFunctor' (which provides 'hmap') and+'HTraversable' (which provides 'htraverse'). These are higher-ranked analogues+of 'Functor' and 'Traversable' from @base@. Compare the type signatures of+'fmap' and 'hmap':++@+'fmap' :: ('Functor' f) => (a -> b) -> f a -> f b+'hmap' :: ('HFunctor' h) => (forall b. s b -> t b) -> h s a -> h t a+@++'fmap' transforms the @*@-kinded type argument to @f@, while 'hmap' transforms+the @(* -> *)@-kinded type constructor argument to @h@.++So in order for an operator to have an instance of 'HFunctor', it must be+possible to swap out sub-expressions inside it. This is the case for our+'SimpleOp'.++'HTraversable' has a similar relationship with 'Traversable'. 'htraverse'+adds an applicative context to 'hmap'\'s transformations:++@+'traverse' :: ('Traversable' t, 'Applicative' f) => (a -> f b) -> t a -> f (t b)+'htraverse' :: ('HTraversable' h, 'Applicative' f) => (forall b. s b -> f (t b)) -> h s a -> f (h t a)+@++There is a default implementation of 'hmap' in terms of 'htraverse'.+-}++instance HFunctor SimpleOp+instance HTraversable SimpleOp where+  htraverse f = \case+    Add x y -> Add <$> f x <*> f y+    Equal x y -> Equal <$> f x <*> f y+    IfThenElse x y z -> IfThenElse <$> f x <*> f y <*> f z+    Literal x -> pure (Literal x)++--------------------------------------------------------------------------------+-- * Variables++{-$+As well as operators, expressions contain variables. Variables are also strongly+typed. A variable type @v@ has kind @* -> *@. The type parameter tells us the+type of the value that the variable is meant to represent.+-}+++{-|+Notice that @a@ is a phantom type here (and it will be for most variable type+constructors). It is only used to restrict the type of values that are+representable by these variables. In this case, we only want to be able to store+integers so the only constructor has return type 'Integer'. It also contains a+'String' to be used as the variable name.+-}+data SimpleVar a where+  SimpleVar :: String -> SimpleVar Integer++--------------------------------------------------------------------------------+-- * Expressions++{-|+Now that we have defined our operators and variables, @'HFree' 'SimpleOp'+'SimpleVar' a@ is a syntax tree for a strongly typed expresson language.+-}+type SimpleExpr = HFree SimpleOp SimpleVar++--------------------------------------------------------------------------------+-- * A DSL++{-$+We can write simple wrapper functions to form a DSL for our expression language.+-}++{-|++@+var = 'hpure' . 'SimpleVar'+@++-}+var :: String -> SimpleExpr Integer+var = hpure . SimpleVar++{-|++@+x ^+ y = 'HWrap' ('Add' x y)+@++-}+(^+) :: SimpleExpr Integer -> SimpleExpr Integer -> SimpleExpr Integer+x ^+ y = HWrap (Add x y)++{-|++@+x ^== y = 'HWrap' ('Equal' x y)+@++-}+(^==) :: SimpleExpr Integer -> SimpleExpr Integer -> SimpleExpr Bool+x ^== y = HWrap (Equal x y)++{-|++@+ifThenElse x y z = 'HWrap' ('IfThenElse' x y z)+@++-}+ifThenElse :: SimpleExpr Bool -> SimpleExpr Integer -> SimpleExpr Integer -> SimpleExpr Integer+ifThenElse x y z = HWrap (IfThenElse x y z)++{-|++@+lit = 'HWrap' . 'Literal'+@++-}+lit :: Integer -> SimpleExpr Integer+lit = HWrap . Literal++--------------------------------------------------------------------------------+-- ** Example Expression++{-|+Here's an example of expression written using this DSL.++@+exampleExpr = 'ifThenElse' ('var' "x" '.==' 'lit' 10) ('var' "y") ('var' "y" '.+' 'lit' 5)+exampleExpr ~ if (x = 10) then y else y + 5+@+-}+exampleExpr :: SimpleExpr Integer+exampleExpr = ifThenElse (var "x" ^== lit 10) (var "y") (var "y" ^+ lit 5)++--------------------------------------------------------------------------------+-- * Expression Manipulation++{-$+If @op@ is an 'HFunctor', then @'HFree' op@ is an 'HMonad'. 'HMonad' defines+'hpure' (c.f. 'pure' or 'return'):++@+'hpure' :: ('HMonad' h) => t a -> h t a+'return' :: ('Monad' m) => a -> m a+@++and '^>>=' (c.f. '>>='):++@+('>>=') :: ('Monad' m) => m a -> (a -> m b) -> m b+('^>>=') :: ('HMonad' h) => h s a -> (forall b. s b -> h t b) -> h t a+@++In the case of @'HFree' op@, 'hpure' produces an expression containing a single+variable:++@+'hpure' :: v a -> 'HFree' op v a+@+-}++-- ** Substitution++{-$+'^>>=' substitutes variables inside expressions.+-}++{-|+'exampleExpr', with @x@ replaced by @z + 5@.++@+exampleExpr2 =+  exampleExpr '^>>=' \v@('SimpleVar' nm) ->+  if nm == "x" then 'var' "x" '^+' 'lit' 5 else 'hpure' v++exampleExpr2 ~ if ((z + 5) = 10) then y else y + 5+@++-}+exampleExpr2 :: SimpleExpr Integer+exampleExpr2 =+  exampleExpr ^>>= \v@(SimpleVar nm) ->+  if nm == "x" then var "z" ^+ lit 5 else hpure v++-- ** Traversal++{-$+When @op@ is an 'HTraversable', 'HFree' is also an 'HTraversable'. This can be+used, for example, to evaluate variables in an expression.+-}++{-|+This is a function that knows the value of variables with certain names. It will+return 'Nothing' if it doesn't know how to evaluate a particular variable.++@+evalXOrY ('SimpleVar' "x") = 'Just' 1+evalXOrY ('SimpleVar' "y") = 'Just' 2+evalXOrY _ = 'Nothing'+@++It might seem strange that we can return @'Just' ('Identity' 1)@ when the+function says it returns a @'Maybe' ('Identity' a)@ for polymorphic @a@. This+works because the constructor 'SimpleVar' must be 'Integer'-valued, so when we match+on it, GHC generates the constraint @a ~ 'Integer'@ and it will happily accept an+'Integer'.++Notice that, for @s ~ 'SimpleVar'@, @t ~ 'Identity'@ and @f ~ 'Maybe'@,++@+evalXOrY :: forall a. s a -> f (t a)+@++This means that we can traverse using this function:++>>> htraverse evalXOrY exampleExpr+htraverse evalXOrY exampleExpr :: Maybe (HFree SimpleOp Identity Integer)+htraverse evalXOrY exampleExpr ~ Just (if (1 = 10) then 2 else 2 + 5)++>>> htraverse evalXOrY exampleExpr2+htraverse evalXOrY exampleExpr2 :: Maybe (HFree SimpleOp Identity Integer)+htraverse evalXOrY exampleExpr2 ~ Nothing++There was a variable (@z@) that @evalXOrY@ didn't know how to evaluate, so the+traversal resulted in 'Nothing'!++-}+evalXOrY :: SimpleVar a -> Maybe (Identity a)+evalXOrY (SimpleVar "x") = Just (Identity 1)+evalXOrY (SimpleVar "y") = Just (Identity 2)+evalXOrY _               = Nothing++--------------------------------------------------------------------------------+-- * Evaluating Expressions++{-$+The 'HFoldableAt' type class provides the mechanism for evaluating operators,+and hence expressions.++@+'hfoldMap' :: ('HFoldableAt' k h) => (forall b. t b -> k b) -> h t b -> k b+@++Implemented in terms of this is++@+'hfoldTraverse'+  :: ('HFoldableAt' k h, 'HTraversable' h, 'Applicative' f)+  => (forall b. t b -> f (k b))+  -> h t a+  -> f (k a)+'hfoldTraverse' f = 'fmap' ('hfoldMap' 'id') . 'htraverse' f+@++This function will allow us to evaluate our expressions to ground values:++>>> hfoldTraverse evalXOrY exampleExpr+Just (Identity 7)++>>> hfoldTraverse evalXOrY exampleExpr2+Nothing++-}++instance HFoldableAt Identity SimpleOp where+  hfoldMap f s = case s of+    Add x y -> (+) <$> f x <*> f y+    Equal x y -> (==) <$> f x <*> f y+    IfThenElse x y z ->+      let ite' c a b = if c then a else b+      in ite' <$> f x <*> f y <*> f z+    Literal x -> pure x++--------------------------------------------------------------------------------+-- ** Evaluating Variables Symbolically++{-$+With the help of @sbv@, we can evaluate expressions symbolically in order to+prove things about them.+-}++{-|+Here's a function that converts variables in 'SimpleVar' to symbolic values. It+needs a @'Map' 'String' ('SBV' 'Integer')@ stateful environment in order to+remember variables that already have symbolic values, because 'SBV' will give+you different variables on two different calls of @'symbolic' x@ for the same+@x@.+-}+evalVarSymbolic :: SimpleVar a -> StateT (Map String (SBV Integer)) Symbolic (SBV a)+evalVarSymbolic (SimpleVar nm) = do+  existingSymbol <- gets (Map.lookup nm)+  case existingSymbol of+    Just x -> return x+    Nothing -> do+      newSymbol <- lift (symbolic nm)+      modify (Map.insert nm newSymbol)+      return newSymbol++--------------------------------------------------------------------------------+-- ** Evaluating Expressions Symbolically++{-$+We need an instance of @'HFoldableAt' 'SBV' 'SimpleOp'@ to do symbolic+evaluation, implemented like so:++@+instance 'HFoldableAt' 'SBV' 'SimpleOp' where+  'hfoldMap' = 'implHfoldMap' $ \s -> case s of+    'Add' x y          -> x '+' y+    'Equal' x y        -> x '.==' y+    'IfThenElse' x y z -> 'ite' x y z+    'Literal' x        -> 'literal' x+@+-}++instance HFoldableAt SBV SimpleOp where+  hfoldMap = implHfoldMap $ \s -> case s of+    Add x y          -> x + y+    Equal x y        -> x .== y+    IfThenElse x y z -> ite x y z+    Literal x        -> literal x++{-|+Now we can evaluate expressions symbolically and use @sbv@ to prove things about+them.++@+evalSimpleExprSymbolic = 'hfoldTraverse' 'evalVarSymbolic'+@+-}+evalSimpleExprSymbolic :: SimpleExpr a -> StateT (Map String (SBV Integer)) Symbolic (SBV a)+evalSimpleExprSymbolic = hfoldTraverse evalVarSymbolic++{-|++Let's ask @sbv@ to prove that our expression always returns a value no less than+the variable @y@.++@+examplePredicate = 'flip' 'evalStateT' 'mempty' $ do+  expr <- 'evalSimpleExprSymbolic' 'exampleExpr'+  y <- 'evalSimpleExprSymbolic' ('var' "y")+  'return' ('expr' '.>=' y)+@++>>> isTheorem examplePredicate+True++-}+examplePredicate :: Predicate+examplePredicate = flip evalStateT mempty $ do+  expr <- evalSimpleExprSymbolic exampleExpr+  y <- evalSimpleExprSymbolic (var "y")+  return (expr .>= y)
+ Language/Expression/GeneralOp.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE KindSignatures        #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeOperators         #-}++module Language.Expression.GeneralOp where++-- import           Data.Typeable++import           Data.Vinyl+-- import           Data.Vinyl.Functor+-- import           Data.Vinyl.TypeLevel++import           Language.Expression+import           Language.Expression.Pretty++data GeneralOp op t a where+  Op :: op as r -> Rec t as -> GeneralOp op t r++class EvalOpAt k op where+  evalMany :: op as r -> Rec k as -> k r++-- class EqOpMany op where+--   liftEqMany+--     :: op as a -> op bs b++--     -> (forall xs. (AllConstrained Eq xs, RecApplicative xs) =>+--         Rec f xs -> Rec g xs -> Bool)++--     -> Rec f as -> Rec g bs -> Bool+++class PrettyOp op where+  prettysPrecOp :: Pretty1 t => Int -> op as a -> Rec t as -> ShowS++instance HFunctor (GeneralOp op) where++instance HTraversable (GeneralOp op) where+  htraverse f = \case+    Op o args -> Op o <$> rtraverse f args+++instance (EvalOpAt k op) => HFoldableAt k (GeneralOp op) where+  hfoldMap f = \case+    Op o args -> evalMany o (rmap f args)+++-- instance EqOpMany op => HEq (GeneralOp op) where+--   liftHEq le _ (Op o1 (xs :: Rec f as)) (Op o2 (ys :: Rec g bs)) =+--     liftEqMany o1 o2 liftEqAll xs ys++--     where+--       liftEqAll+--         :: (AllConstrained Eq xs, RecApplicative xs)+--         => Rec f xs -> Rec g xs -> Bool+--       liftEqAll (xs' :: Rec f xs) ys' =+--         let+--           eqList :: Rec (Lift (->) f (Lift (->) g (Const Bool))) xs+--           eqList = rpureConstrained (Proxy :: Proxy Eq)+--             (Lift $ \x -> Lift $ Const . le (==) x)+--         in and . recordToList $ eqList <<*>> xs' <<*>> ys'++instance PrettyOp op => Pretty2 (GeneralOp op) where+  prettys2Prec p = \case+    Op op args -> prettysPrecOp p op args
+ Language/Expression/Pretty.hs view
@@ -0,0 +1,179 @@+{-# LANGUAGE DataKinds                 #-}+{-# LANGUAGE EmptyCase                 #-}+{-# LANGUAGE FlexibleContexts          #-}+{-# LANGUAGE FlexibleInstances         #-}+{-# LANGUAGE LambdaCase                #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE PolyKinds                 #-}+{-# LANGUAGE TypeFamilies              #-}+{-# LANGUAGE TypeOperators             #-}+{-# LANGUAGE UndecidableInstances      #-}++{-|++Pretty printing for expressions.++-}+module Language.Expression.Pretty+  (+  -- * Classes+    Pretty(..)+  , prettys+  , Pretty1(..)+  , prettys1+  , Pretty2(..)+  , prettys2+  , Pretty3(..)+  , prettys3+  -- * Combinators+  , putPretty+  , prettys1PrecBinop+  , prettys1PrecUnop+  ) where++import           Data.Functor.Const+import           Data.List                  (intersperse)+import           Data.Monoid                (Endo (..))++import           Language.Expression+import           Language.Expression.Choice+import           Language.Expression.Scope++--------------------------------------------------------------------------------+--  Convenience+--------------------------------------------------------------------------------++putPretty :: Pretty a => a -> IO ()+putPretty = putStrLn . pretty++--------------------------------------------------------------------------------+--  Combinators+--------------------------------------------------------------------------------++prettys1PrecUnop :: Pretty1 t => Int -> String -> Int -> t a -> ShowS+prettys1PrecUnop opPrec opStr p x =+  showParen (p > opPrec) $ showString opStr . prettys1Prec (opPrec + 1) x++prettys1PrecBinop+  :: (Pretty1 f, Pretty1 g)+  => Int -> String -> Int -> f a -> g b -> ShowS+prettys1PrecBinop opPrec opStr p x y =+  showParen (p > opPrec) $+  prettys1Prec (opPrec + 1) x . showString opStr . prettys1Prec (opPrec + 1) y++--------------------------------------------------------------------------------+--  Pretty typeclasses+--------------------------------------------------------------------------------++prettys :: Pretty a => a -> ShowS+prettys = prettysPrec 0++prettys1 :: Pretty1 t => t a -> ShowS+prettys1 = prettys1Prec 0++prettys2 :: (Pretty2 op, Pretty1 t) => op t a -> ShowS+prettys2 = prettys2Prec 0++prettys3 :: (Pretty3 h, Pretty2 s, Pretty1 t) => h s t a -> ShowS+prettys3 = prettys3Prec 0++class Pretty a where+  {-# MINIMAL pretty | prettysPrec #-}++  pretty :: a -> String+  prettysPrec :: Int -> a -> ShowS++  pretty x = prettys x ""+  prettysPrec _ x s = pretty x ++ s++class Pretty1 t where+  {-# MINIMAL pretty1 | prettys1Prec #-}++  pretty1 :: t a -> String+  pretty1 x = prettys1 x ""++  prettys1Prec :: Int -> t a -> ShowS+  prettys1Prec _ x s = pretty1 x ++ s++class Pretty2 op where+  {-# MINIMAL pretty2 | prettys2Prec #-}++  pretty2 :: (Pretty1 t) => op t a -> String+  pretty2 x = prettys2 x ""++  prettys2Prec :: (Pretty1 t) => Int -> op t a -> ShowS+  prettys2Prec _ x s = pretty2 x ++ s++class Pretty3 h where+  {-# MINIMAL pretty3 | prettys3Prec #-}++  pretty3 :: (Pretty2 s, Pretty1 t) => h s t a -> String+  pretty3 x = prettys3 x ""++  prettys3Prec :: (Pretty2 s, Pretty1 t) => Int -> h s t a -> ShowS+  prettys3Prec _ x s = pretty3 x ++ s++--------------------------------------------------------------------------------+--  Combinatory instances+--------------------------------------------------------------------------------++instance {-# OVERLAPPABLE #-} (Pretty1 t) => Pretty (t a) where+  prettysPrec = prettys1Prec++instance {-# OVERLAPPABLE #-} (Pretty2 f, Pretty1 t) => Pretty1 (f t) where+  prettys1Prec = prettys2Prec++instance {-# OVERLAPPABLE #-} (Pretty3 h, Pretty2 s) => Pretty2 (h s) where+  prettys2Prec = prettys3Prec++instance Pretty1 (Const String) where+  pretty1 (Const x) = x++instance (Pretty2 op) => Pretty2 (HFree op) where+  prettys2Prec p = \case+    HPure x -> prettys1Prec p x+    HWrap op -> prettys2Prec p op++instance (Pretty1 t) => Pretty2 (BV t) where+  prettys2Prec p = foldBV (prettys1Prec p) (prettys1Prec p)++instance (Pretty2 h, Pretty1 t) => Pretty2 (Scope t h) where+  prettys2Prec p (Scope x) = prettys2Prec p x++instance (Pretty2 h, Pretty1 t) => Pretty2 (Scoped h t) where+  prettys2Prec p (Scoped x) = prettys2Prec p x+++instance (Pretty3 h) => Pretty2 (SFree h) where+  prettys2Prec p = \case+    SPure x -> prettys1Prec p x+    SWrap x -> prettys3Prec p x+++instance (Pretty2 (OpChoice ops)) => Pretty2 (HFree' ops) where+  prettys2Prec p = prettys2Prec p . getHFree'++instance (Pretty2 (OpChoice '[])) where+  pretty2 = noOps+++instance (Pretty2 op, Pretty2 (OpChoice ops)) =>+         Pretty2 (OpChoice (op : ops)) where+  prettys2Prec p = \case+    OpThis x -> prettys2Prec p x+    OpThat x -> prettys2Prec p x++instance {-# OVERLAPPING #-} Pretty String where+  pretty = id++instance {-# OVERLAPPING #-} Pretty a => Pretty [a] where+  prettysPrec _ xs = (appEndo . mconcat . map Endo) (+    showString "[ " : (intersperse (showString "\n, ") . map prettys) xs) .+    showString "\n]"++instance {-# OVERLAPPING #-} Pretty a => Pretty (Maybe a) where+  prettysPrec p (Just x) = prettysPrec p x+  prettysPrec _ Nothing  = \r -> "<nothing>" ++ r++instance Pretty () where+  pretty = show
+ Language/Expression/Prop.hs view
@@ -0,0 +1,170 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}++{-|++Propositions and combinators for conveniently constructing them.++-}+module Language.Expression.Prop+  (+    -- * Proposition Types+    Prop+  , Prop'+    -- * DSL+  , expr+  , plit+  , pnot+  , (*&&)+  , (*||)+  , (*->)+  , (*<->)+  , propAnd+  , propOr+    -- * HTraversable+  , LogicOp(..)+  ) where++import           Control.Applicative        (liftA2)+import           Data.List                  (foldl')+-- import           Data.Typeable++-- import           Data.Functor.Classes+import           Data.Functor.Identity++import           Data.SBV++import           Language.Expression+import           Language.Expression.Choice+import           Language.Expression.Pretty+import           Language.Expression.Util++-- | Propositions over general expressions.+type Prop = HFree LogicOp++-- | Propositions over expressions with the given list of operators.+type Prop' ops v = Prop (HFree' ops v)++--------------------------------------------------------------------------------+--  DSL+--------------------------------------------------------------------------------++infixl 3 *&&+infixl 2 *||+infixr 1 *->+infix 1 *<->++-- | Lift an expression into the land of propositions.+expr :: expr a -> Prop expr a+expr = HPure++plit :: Bool -> Prop expr Bool+plit = HWrap . LogLit++pnot :: Prop expr Bool -> Prop expr Bool+pnot = HWrap . LogNot++(*&&) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool+(*&&) = HWrap ... LogAnd++(*||) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool+(*||) = HWrap ... LogOr++(*->) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool+(*->) = HWrap ... LogImpl++(*<->) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool+(*<->) = HWrap ... LogEquiv++propAnd :: [Prop expr Bool] -> Prop expr Bool+propAnd []       = plit True+propAnd (x : xs) = foldl' (*&&) x xs++propOr :: [Prop expr Bool] -> Prop expr Bool+propOr []       = plit False+propOr (x : xs) = foldl' (*||) x xs+++--------------------------------------------------------------------------------+--  The HTraversable+--------------------------------------------------------------------------------++-- | Logical operations+data LogicOp t a where+  LogLit :: Bool -> LogicOp t Bool+  LogNot :: t Bool -> LogicOp t Bool+  LogAnd :: t Bool -> t Bool -> LogicOp t Bool+  LogOr :: t Bool -> t Bool -> LogicOp t Bool+  LogImpl :: t Bool -> t Bool -> LogicOp t Bool+  LogEquiv :: t Bool -> t Bool -> LogicOp t Bool++instance HFunctor LogicOp+instance HTraversable LogicOp where+  htraverse f = \case+    LogLit b -> pure $ LogLit b+    LogNot x -> LogNot <$> f x+    LogAnd x y -> LogAnd <$> f x <*> f y+    LogOr x y -> LogOr <$> f x <*> f y+    LogImpl x y -> LogImpl <$> f x <*> f y+    LogEquiv x y -> LogEquiv <$> f x <*> f y++instance HFoldableAt Identity LogicOp where+  hfoldMap = implHfoldMap $ \case+    LogLit b -> pure b+    LogNot x -> not <$> x+    LogAnd x y -> liftA2 (&&) x y+    LogOr x y -> liftA2 (||) x y+    LogImpl x y -> liftA2 (==>) x y+    LogEquiv x y -> liftA2 (<=>) x y++instance HFoldableAt SBV LogicOp where+  hfoldMap = implHfoldMap $ \case+    LogLit b -> fromBool b+    LogNot x -> bnot x+    LogAnd x y -> x &&& y+    LogOr x y -> x ||| y+    LogImpl x y -> x ==> y+    LogEquiv x y -> x <=> y++-- instance HEq LogicOp where+--   liftHEq _ _ (LogLit x) (LogLit y) = x == y+--   liftHEq le _ (LogNot x) (LogNot y) = le svEq x y+--   liftHEq le _ (LogAnd x1 x2) (LogAnd y1 y2) = le svEq x1 y1 && le svEq x2 y2+--   liftHEq le _ (LogOr x1 x2) (LogOr y1 y2) = le svEq x1 y1 && le svEq x2 y2+--   liftHEq le _ (LogImpl x1 x2) (LogImpl y1 y2) = le svEq x1 y1 && le svEq x2 y2+--   liftHEq le _ (LogEquiv x1 x2) (LogEquiv y1 y2) = le svEq x1 y1 && le svEq x2 y2+--   liftHEq _ _ _ _ = False++-- instance (Eq1 t) => Eq1 (LogicOp t) where liftEq = liftLiftEq++-- instance (Eq a, Eq1 t) => Eq (LogicOp t a) where (==) = eq1++instance Pretty2 LogicOp where+  prettys2Prec p = \case+    LogLit True -> \r -> "T" ++ r+    LogLit False -> \r -> "F" ++ r+    LogNot x -> showParen (p > 8) $ showString "¬ " . prettys1Prec 9 x+    LogAnd x y ->+      showParen (p > 3) $ prettys1Prec 4 x . showString " ∧ " . prettys1Prec 4 y+    LogOr  x y ->+      showParen (p > 2) $ prettys1Prec 3 x . showString " ∨ " . prettys1Prec 3 y+    LogImpl  x y ->+      showParen (p > 1) $ prettys1Prec 2 x . showString " -> " . prettys1Prec 2 y+    LogEquiv  x y ->+      showParen (p > 0) $ prettys1Prec 1 x . showString " <-> " . prettys1Prec 1 y++--------------------------------------------------------------------------------+--  Internal Combinators+--------------------------------------------------------------------------------++-- svEq :: (Typeable a, Typeable b, Eq a) => a -> b -> Bool+-- svEq (x :: a) (y :: b)+--   | Just Refl <- eqT :: Maybe (a :~: b) = x == y+--   | otherwise = False
+ Language/Expression/Scope.hs view
@@ -0,0 +1,190 @@+{-# LANGUAGE FlexibleInstances         #-}+{-# LANGUAGE GADTs                     #-}+{-# LANGUAGE LambdaCase                #-}+{-# LANGUAGE MultiParamTypeClasses     #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# LANGUAGE PolyKinds                 #-}+{-# LANGUAGE RankNTypes                #-}+{-# LANGUAGE TypeOperators             #-}++module Language.Expression.Scope where++import           Control.Lens++import           Language.Expression++--------------------------------------------------------------------------------+--  Classes+--------------------------------------------------------------------------------++class HBound k where+  (^>>>=) :: (HMonad h) => k h t a -> (forall b. t b -> h t' b) -> k h t' a++--------------------------------------------------------------------------------+--  Bound or free variables+--------------------------------------------------------------------------------++data BV g f a where+  -- | Bound variable+  B :: g a -> BV g f a+  -- | Free variable+  F :: f a -> BV g f a++instance HFunctor (BV g) where+  hmap = hliftM++instance HPointed (BV g) where+  hpure = F++instance HBind (BV g) where+  B x ^>>= _ = B x+  F x ^>>= f = f x++instance HMonad (BV g)++-- instance (HFoldableAt k g) => HFoldableAt k (BV g) where+--   hfoldMap = hbifoldMap . hfoldMap++instance HTraversable (BV g) where+  htraverse = hbitraverseBV pure++foldBV :: (w a -> r) -> (v a -> r) -> BV w v a -> r+foldBV f g = \case+  B x -> f x+  F y -> g y++instance HBifunctor BV where+  hbimap = hbimapBV++instance HBitraversable BV where+  hbitraverse = hbitraverseBV++hbitraverseBV :: (Functor t) => (g a -> t (g' b)) -> (f a -> t (f' b)) -> BV g f a -> t (BV g' f' b)+hbitraverseBV f g = foldBV (fmap B . f) (fmap F . g)++hbimapBV :: (g a -> g' b) -> (f a -> f' b) -> BV g f a -> BV g' f' b+hbimapBV f g = foldBV (B . f) (F . g)++instance HBifoldableAt k BV where+  hbifoldMap = foldBV++--------------------------------------------------------------------------------+--  Scopes+--------------------------------------------------------------------------------++newtype Scope g h f a = Scope { unscope :: h (BV g (h f)) a }++_Scope :: Iso (Scope g h f a) (Scope g' h' f' a') (h (BV g (h f)) a) (h' (BV g' (h' f')) a')+_Scope = iso unscope Scope++instance HFunctor h => HFunctor (Scope g h) where+  hmap f = from _Scoped %~ hfirst f++instance HPointed h => HPointed (Scope g h) where+  hpure = Scope . hpure . hpure . hpure++instance HTraversable h => HTraversable (Scope g h) where+  htraverse f = _Scope %%~ htraverse (htraverse (htraverse f))+++instance HDuofunctor (Scope g) where+  hduomap g f = _Scope %~ g (hmap (g f))++instance HDuotraversable (Scope g) where+  hduotraverse g f = _Scope %%~ g (htraverse (g f))+++instance HBound (Scope g) where+  Scope x ^>>>= f = Scope (x ^>>= foldBV (hpure . B) (hmap (F . f)))+++hbitraverseScope+  :: (Applicative t, HTraversable h)+  => (forall b. g b -> t (g' b))+  -> (forall b. f b -> t (f' b))+  -> Scope g h f a+  -> t (Scope g' h f' a)+hbitraverseScope g f = from _Scoped %%~ hbitraverse f g+++freeVar :: (HPointed h) => f a -> Scope g h f a+freeVar = Scope . hpure . hpure . hpure+++boundVar :: (HPointed h) => g a -> Scope g h f a+boundVar = Scope . hpure . B+++liftScope :: (HFunctor h, HPointed h) => h f a -> Scope g h f a+liftScope = Scope . hmap (hpure . hpure)+++abstractTraverse :: (HMonad h, HTraversable h, Applicative t) => (forall b. f b -> t (Maybe (g b))) -> h f a -> t (Scope g h f a)+abstractTraverse f = fmap Scope . htraverse (\y -> maybe ((hpure . hpure) y) B <$> f y)+++abstract :: (HMonad h) => (forall b. f b -> Maybe (g b)) -> h f a -> Scope g h f a+abstract f = Scope . hmap (\y -> maybe ((hpure . hpure) y) B $ f y)+++-- instantiate :: (Substitutive op, Applicative f) => (forall b. w b -> f (op v b)) -> Scope g h f a -> f (op v a)+-- instantiate f (Scope x) = bindVars (foldBV f pure) x++-- | Sometimes it's convenient to move around the type arguments to 'Scope'.+newtype Scoped h f g a = Scoped { unscoped :: Scope g h f a }++_Scoped :: Iso (Scoped h f g a) (Scoped h' f' g' a') (Scope g h f a) (Scope g' h' f' a')+_Scoped = iso unscoped Scoped++instance HFunctor h => HFunctor (Scoped h f) where+  hmap = hsecond++instance HFunctor h => HBifunctor (Scoped h) where+  hbimap f g = _Scoped . _Scope %~ hmap (hbimap g (hmap f))++instance HTraversable h => HBitraversable (Scoped h) where+  hbitraverse f g = _Scoped . _Scope %%~ htraverse (hbitraverse g (htraverse f))++instance HTraversable h => HTraversable (Scoped h f) where+  htraverse = hbitraverse pure++--------------------------------------------------------------------------------+--  Scoped Free Monads+--------------------------------------------------------------------------------++data SFree h f a+  = SPure (f a)+  | SWrap (h (Scoped (SFree h) f) (SFree h f) a)++instance HDuofunctor h => HFunctor (SFree h) where+  hmap = hliftM++instance HPointed (SFree h) where+  hpure = SPure++instance HDuofunctor h => HBind (SFree h) where+  SPure x ^>>= f = f x+  SWrap x ^>>= f = SWrap (hduomap (\g -> (\(Scoped y) -> Scoped (y ^>>>= f)) . hmap g) (^>>= f) x)++instance HDuofunctor h => HMonad (SFree h)++instance (HDuotraversable h) => HTraversable (SFree h) where+  htraverse f = \case+    SPure x -> SPure <$> f x+    SWrap x -> SWrap <$> hduotraverse (hbitraverse f) (htraverse f) x+++instance HDuofoldableAt k (Scope k) where+  hduofoldMap f g = f (hbifoldMap id (f g)) . view _Scope++instance (HFunctor h, HFoldableAt k h) => HBifoldableAt k (Scoped h) where+  hbifoldMap f g = hfoldMap (hbifoldMap g (hfoldMap f)) . view (_Scoped . _Scope)++instance (HDuotraversable h, HDuofoldableAt k h) => HFoldableAt k (SFree h) where+  hfoldMap f = \case+    SPure x -> f x+    SWrap x ->+      hduofoldMap+      (\g -> hduofoldMap hfoldMap f . view _Scoped . hsecond g)+      (hfoldMap f)+      x
+ Language/Expression/Util.hs view
@@ -0,0 +1,4 @@+module Language.Expression.Util where++(...) :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)+(f ... g) x y = f (g x y)
+ Language/Verification.hs view
@@ -0,0 +1,44 @@+{-|++Strongly-typed utilities to aid in automatic verification (e.g. of programs)+using an SMT solver.++This is mainly just a wrapper around "Data.SBV" that allows for inspection and+manipulation of symbolic values, especially variable substitution.++-}+module Language.Verification+  (+  -- * The verification monad+    Verifier+  , runVerifier+  , runVerifierWith+  , VerifierError(..)++  -- * The query monad+  , Query+  , query++  -- * Verifiable variables+  , VerifiableVar(..)++  -- * Verifier actions+  , evalProp+  , evalProp'+  , evalPropSimple++  -- * Miscellaneous combinators+  , subVar++  -- * Expressions+  , module Expression++  -- * SBV re-exports+  , SMTConfig(..)+  , defaultSMTCfg+  ) where++import           Data.SBV                   (SMTConfig (..), defaultSMTCfg)++import           Language.Expression        as Expression+import           Language.Verification.Core
+ Language/Verification/Conditions.hs view
@@ -0,0 +1,254 @@+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE DeriveFunctor         #-}+{-# LANGUAGE DeriveTraversable     #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE KindSignatures        #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}++{- |++Combinators for generating verification conditions for programs.++-}+module Language.Verification.Conditions+  (+  -- * Types+    Assignment(..)+  , AnnSeq(..)+  , Triplet++  -- * Generating Verification Conditions+  , skipVCs+  , assignVCs+  , sequenceVCs+  , ifVCs+  , multiIfVCs+  , whileVCs++  -- * Combinators+  , subAssignment+  , chainSub+  , joinAnnSeq+  , JoinAnnSeq(..)+  , joiningAnnSeq+  , emptyAnnSeq+  , propAnnSeq+  , cmdAnnSeq++  -- * Propositions+  , module Language.Expression.Prop+  ) where++import           Data.List                  (intersperse)+import           Data.Semigroup             (Semigroup(..))+import           Data.Monoid                (Endo (..))++import           Control.Monad.Writer       (MonadWriter (tell))++import           Language.Expression.Pretty+import           Language.Expression.Prop+import           Language.Verification++--------------------------------------------------------------------------------+--  Exposed Types+--------------------------------------------------------------------------------++-- | An assignment of a particular expression to a particular variable.+data Assignment expr var where+  Assignment :: var a -> expr var a -> Assignment expr var++instance (Pretty1 var, Pretty2 expr) => Pretty (Assignment expr var) where+  prettysPrec p (Assignment v e) = showParen (p > 9) $+    prettys1Prec 10 v . showString " := " . prettys2Prec 10 e++-- | An annotated sequence. Consists of runs of assignments, with other commands+-- separated by annotations.+data AnnSeq expr var cmd+  = JustAssign [Assignment expr var]+  -- ^ Just a series of assignments without annotations+  | CmdAssign cmd [Assignment expr var]+  -- ^ A command followed by a series of assignments+  | Annotation (AnnSeq expr var cmd) (Prop (expr var) Bool) (AnnSeq expr var cmd)+  -- ^ An initial sequence, followed by an annotation, then another sequence+  deriving (Functor, Foldable, Traversable)++instance (Pretty2 expr, Pretty1 var, Pretty cmd) => Pretty (AnnSeq expr var cmd) where+  prettysPrec _ (JustAssign as)+    = appEndo . mconcat+    . intersperse (Endo (showString "; "))+    . map (Endo . prettysPrec 10)+    $ as++  prettysPrec _ (CmdAssign cmd as)+    =  appEndo . mconcat+      . intersperse (Endo (showString "; "))+      . (Endo (prettysPrec 10 cmd) :)+      . map (Endo . prettysPrec 10)+      $ as++  prettysPrec _ (Annotation l p r)+    = prettysPrec 10 l+    . showString "; {"+    . prettysPrec 10 p+    . showString "}"+    . prettysPrec 10 r++--------------------------------------------------------------------------------+--  Combinators+--------------------------------------------------------------------------------++-- | Substitutes variables in the given proposition based on the given+-- assignment.+subAssignment+  :: (HMonad expr, VerifiableVar v)+  => Assignment expr v -> Prop (expr v) a -> Prop (expr v) a+subAssignment (Assignment targetVar newExpr) = hmap (^>>= subVar newExpr targetVar)+++-- | Chains substitutions, substituting using each assignment in the given list+-- in turn.+chainSub+  :: (HMonad expr, VerifiableVar v)+  => Prop (expr v) Bool -> [Assignment expr v] -> Prop (expr v) Bool+chainSub prop []       = prop+chainSub prop (a : as) = subAssignment a (chainSub prop as)+++-- | Joins two annotations together without a Hoare annotation in between. Fails+-- if this would place two non-assignment commands after each other, because+-- these need an annotation.+joinAnnSeq :: AnnSeq expr var cmd -> AnnSeq expr var cmd -> Maybe (AnnSeq expr var cmd)+joinAnnSeq (JustAssign xs) (JustAssign ys) = return $ JustAssign (xs ++ ys)+joinAnnSeq (CmdAssign cmd xs) (JustAssign ys) = return $ CmdAssign cmd (xs ++ ys)+joinAnnSeq s (JustAssign []) = return s+joinAnnSeq (JustAssign []) s = return s+joinAnnSeq (Annotation l p r) r' = Annotation l p <$> joinAnnSeq r r'+joinAnnSeq l' (Annotation l p r) = (\l'' -> Annotation l'' p r) <$> joinAnnSeq l' l+joinAnnSeq _ _ = Nothing+++emptyAnnSeq :: AnnSeq expr var cmd+emptyAnnSeq = JustAssign []++propAnnSeq :: Prop (expr var) Bool -> AnnSeq expr var cmd+propAnnSeq p = Annotation emptyAnnSeq p emptyAnnSeq++cmdAnnSeq :: cmd -> AnnSeq expr var cmd+cmdAnnSeq c = CmdAssign c []+++-- | 'JoinAnnSeq' forms a 'Monoid' out of 'AnnSeq' by propagating failure to+-- join arising from 'joinAnnSeq'.+newtype JoinAnnSeq expr var cmd = JoinAnnSeq { tryJoinAnnSeq :: Maybe (AnnSeq expr var cmd) }++joiningAnnSeq :: AnnSeq expr var cmd -> JoinAnnSeq expr var cmd+joiningAnnSeq = JoinAnnSeq . Just++instance Semigroup (JoinAnnSeq expr var cmd) where+  JoinAnnSeq (Just x) <> JoinAnnSeq (Just y) = JoinAnnSeq (x `joinAnnSeq` y)+  _ <> _ = JoinAnnSeq Nothing++instance Monoid (JoinAnnSeq expr var cmd) where+  mempty = JoinAnnSeq (Just emptyAnnSeq)+  mappend = (<>)++--------------------------------------------------------------------------------+--  Generating verification conditions+--------------------------------------------------------------------------------++type MonadGenVCs expr var = MonadWriter [Prop (expr var) Bool]++type Triplet expr var a = (Prop (expr var) Bool, Prop (expr var) Bool, a)++-- | Generates verification conditions for a skip statement.+skipVCs+  :: (HMonad expr, MonadGenVCs expr var m)+  => Triplet expr var () -> m ()+skipVCs (precond, postcond, ()) = tell [precond *-> postcond]+++-- | Generates verification conditions for an assignment.+assignVCs+  :: (HMonad expr, MonadGenVCs expr v m, VerifiableVar v)+  => Triplet expr v (Assignment expr v) -> m ()+assignVCs (precond, postcond, assignment) = do+  let postcond' = subAssignment assignment postcond+  tell [precond *-> postcond']+++-- | Generates verification conditions for a sequence of commands.+sequenceVCs+  :: (HMonad expr, MonadGenVCs expr v m, VerifiableVar v)+  => (Triplet expr v cmd -> m a)+  -> Triplet expr v (AnnSeq expr v cmd) -> m [a]+sequenceVCs cmdVCs (precond, postcond, annSeq) =+  case annSeq of+    -- A sequence of assignments can be verified by checking the precondition+    -- implies the postcondition, after substitutions are performed by the+    -- assignments.+    JustAssign as -> do+      tell [precond *-> chainSub postcond as]+      return []++    -- A command followed by a sequence of assignments can be verified by+    -- substituting based on the assignments in the postcondition, then verifying+    -- the command with the new postcondition and original precondition.+    CmdAssign cmd as ->+      let postcond' = chainSub postcond as+      in (: []) <$> cmdVCs (precond, postcond', cmd)++    -- To verify @{P} C_1 ; {R} C_2 {Q}@, verify @{P} C_1 {R}@ and @{R} C_2 {Q}@.+    Annotation l midcond r -> do+      (++) <$> sequenceVCs cmdVCs (precond, midcond, l)+           <*> sequenceVCs cmdVCs (midcond, postcond, r)+++-- | Generates verification conditions for a two-branch if command.+ifVCs+  :: (HMonad expr, MonadGenVCs expr v m)+  => (Triplet expr v cmd -> m a)+  -> (cond -> Prop (expr v) Bool)+  -> Triplet expr v (cond, cmd, cmd) -> m (a, a)+ifVCs cmdVCs condToProp (precond, postcond, (cond, cmd1, cmd2)) = do+  let condProp = condToProp cond+  return (,) <*> cmdVCs ((precond *&& condProp), postcond, cmd1)+             <*> cmdVCs ((precond *&& pnot condProp), postcond, cmd2)+++-- | Generates verification conditions for a multi-branch if-then-else-...+-- command.+multiIfVCs+  :: (HMonad expr, Monad m)+  => (Triplet expr v cmd -> m ())+  -> (cond -> Prop (expr v) Bool)+  -> Triplet expr v [(Maybe cond, cmd)] -> m ()+multiIfVCs cmdVCs condToProp (precond, postcond, branches) = go precond branches+  where+    go precond' ((branchCond, branchCmd) : rest) =+      case branchCond of+        Just bc -> do+          let bc' = condToProp bc+          cmdVCs ((precond' *&& bc'), postcond, branchCmd)+          go (precond' *&& pnot bc') rest+        Nothing -> do+          cmdVCs (precond', postcond, branchCmd)+    go _ [] = return ()+++-- | Generates verification conditions for a while loop.+whileVCs+  :: (HMonad expr, MonadGenVCs expr v m)+  => (Triplet expr v cmd -> m ())+  -> (cond -> Prop (expr v) Bool)+  -> Prop (expr v) Bool -- ^ Loop invariant+  -> Triplet expr v (cond, cmd) -> m ()+whileVCs cmdVCs condToProp invariant (precond, postcond, (cond, body)) = do+  let condProp = condToProp cond+  -- Assert that the invariant is maintained over the loop body+  cmdVCs ((invariant *&& condProp), invariant, body)+  -- Assert that the invariant is implied by precondition, and at the end of the+  -- loop the invariant implies the postcondition+  tell [precond *-> invariant, (invariant *&& pnot condProp) *-> postcond]
+ Language/Verification/Core.hs view
@@ -0,0 +1,223 @@+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE FunctionalDependencies     #-}+{-# LANGUAGE GADTs                      #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE KindSignatures             #-}+{-# LANGUAGE LambdaCase                 #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE NoMonomorphismRestriction  #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE StandaloneDeriving         #-}+{-# LANGUAGE TemplateHaskell            #-}+{-# LANGUAGE TypeFamilies               #-}+{-# LANGUAGE TypeOperators              #-}+{-# LANGUAGE TypeSynonymInstances       #-}+{-# LANGUAGE UndecidableInstances       #-}++module Language.Verification.Core where++import           Control.Exception+import           Data.Typeable            ((:~:) (..), Typeable)+import           Data.Functor.Compose++import           Control.Lens             hiding ((.>))+import           Control.Monad.Except+import           Control.Monad.Reader+import           Control.Monad.State++import           Data.Map                 (Map)+import           Data.SBV                 hiding (OrdSymbolic (..), ( # ))++import           Language.Expression+import           Language.Expression.Prop (LogicOp, Prop)++--------------------------------------------------------------------------------+--  Variables+--------------------------------------------------------------------------------++class (Typeable v, Ord (VarKey v), Show (VarKey v), Typeable (VarKey v)) => VerifiableVar v where+  type VarKey v+  type VarSym v :: * -> *+  type VarEnv v :: *++  symForVar :: v a -> VarEnv v -> Symbolic (VarSym v a)+  varKey :: v a -> VarKey v++  eqVarTypes :: v a -> v b -> Maybe (a :~: b)++  castVarSym :: v a -> VarSym v b -> Maybe (VarSym v a)++--------------------------------------------------------------------------------+--  Verifier Monad+--------------------------------------------------------------------------------++data VerifierError v+  = VEMismatchedSymbolType (VarKey v)+  -- ^ The same variable was used for two different symbol types+  | VESbvException String String+  -- ^ When running a query, SBV threw an exception++deriving instance Show (VarKey v) => Show (VerifierError v)+deriving instance Typeable (VarKey v) => Typeable (VerifierError v)++instance (Typeable v, l ~ VarKey v, Show l, Typeable l) =>+  Exception (VerifierError v) where++  displayException = \case+    VEMismatchedSymbolType l ->+      "variable " ++ show l ++ " was used at two different types"++    VESbvException message (_ {- location -}) ->+      "exception from SBV:\n" ++ message++newtype Verifier v a =+  Verifier+  { getVerifier :: ReaderT SMTConfig (ExceptT (VerifierError v) IO) a+  }+  deriving ( Functor+           , Applicative+           , Monad+           , MonadIO+           , MonadReader SMTConfig+           , MonadError (VerifierError v)+           )++runVerifierWith+  :: (VerifiableVar v)+  => SMTConfig+  -> Verifier v a+  -> IO (Either (VerifierError v) a)+runVerifierWith config (Verifier action) = runExceptT (runReaderT action config)++runVerifier+  :: VerifiableVar v+  => Verifier v a -> IO (Either (VerifierError v) a)+runVerifier = runVerifierWith defaultSMTCfg++--------------------------------------------------------------------------------+--  Query Monad+--------------------------------------------------------------------------------++data SomeSym v where+  SomeSym :: VarSym v a -> SomeSym v++type QueryState v = Map (VarKey v) (SomeSym v)++newtype Query v a =+  Query+  { getQuery :: ReaderT (VarEnv v) (+      StateT (QueryState v) Symbolic) a+  }+  deriving ( Functor+           , Applicative+           , Monad+           , MonadIO+           )++query :: (VerifiableVar v) => Query v SBool -> VarEnv v -> Verifier v Bool+query (Query action) env = do+  cfg <- ask+  let predicate = evalStateT (runReaderT action env) mempty+      smtResult =+        (Right <$> isTheoremWith cfg predicate) `catches`+        [ Handler (\ex -> return (Left ex))+        , Handler (\(ErrorCallWithLocation message location) ->+                     return (Left (VESbvException message location)))+        ]++  liftIO smtResult >>= either throwError return++--------------------------------------------------------------------------------+--  Query actions+--------------------------------------------------------------------------------++evalProp+  :: ( HMonad expr+     , HTraversable expr+     , VerifiableVar v+     , Exception (VerifierError v)+     , HFoldableAt k expr+     , HFoldableAt k LogicOp+     , Monad m+     )+  => (forall a. Query v a -> m a)+  -> (forall a. VarSym v a -> m (k a))+  -> Prop (expr v) b+  -> m (k b)+evalProp liftQuery liftVar = hfoldTraverse (hfoldTraverse (liftVar <=< liftQuery . symbolVar))++evalProp'+  :: ( HMonad expr+     , HTraversable expr+     , VerifiableVar v+     , Exception (VerifierError v)+     , HFoldableAt (Compose m k) expr+     , HFoldableAt (Compose m k) LogicOp+     , Monad m+     )+  => (forall a. Query v a -> m a)+  -> (forall a. VarSym v a -> m (k a))+  -> Prop (expr v) b+  -> m (k b)+evalProp' liftQuery liftVar = hfoldMapA (hfoldMapA (liftVar <=< liftQuery . symbolVar))++evalPropSimple+  :: ( HMonad expr+     , HTraversable expr+     , VerifiableVar v+     , Exception (VerifierError v)+     , HFoldableAt SBV expr+     , VarSym v ~ SBV+     )+  => Prop (expr v) b+  -> Query v (SBV b)+evalPropSimple = evalProp id pure++--------------------------------------------------------------------------------+--  Combinators+--------------------------------------------------------------------------------++-- | If the two variables match in both type and name, return the given+-- expression. Otherwise, return an expression just containing this variable.+--+-- This is substitution into an expression, where the old expression is just a+-- variable.+subVar+  :: (HPointed expr, VerifiableVar v, Eq (VarKey v))+  => expr v a+  -> v a+  -> v b+  -> expr v b+subVar newExpr targetVar thisVar =+  let targetName = varKey targetVar+      thisName = varKey thisVar+  in case eqVarTypes thisVar targetVar of+       Just Refl | thisName == targetName -> newExpr+       _         -> hpure thisVar++--------------------------------------------------------------------------------+--  Internal Functions+--------------------------------------------------------------------------------++liftSymbolic :: Symbolic a -> Query v a+liftSymbolic = Query . lift . lift++throwQuery :: (Exception (VerifierError v)) => VerifierError v -> Query v a+throwQuery = liftIO . throwIO++symbolVar :: (VerifiableVar v, Exception (VerifierError v)) => v a -> Query v (VarSym v a)+symbolVar theVar = do+  let varLoc = varKey theVar+  storedSymbol <- Query $ use (at varLoc)++  case storedSymbol of+    Just (SomeSym x) -> case castVarSym theVar x of+      Just y  -> return y+      Nothing -> throwQuery (VEMismatchedSymbolType varLoc)+    Nothing -> do+      newSymbol <- liftSymbolic . symForVar theVar =<< Query ask+      Query $ at varLoc .= Just (SomeSym newSymbol)+      return newSymbol
+ Language/While/Hoare.hs view
@@ -0,0 +1,95 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DataKinds          #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFunctor      #-}+{-# LANGUAGE DeriveTraversable  #-}+{-# LANGUAGE GADTs              #-}+{-# LANGUAGE LambdaCase         #-}+{-# LANGUAGE TypeFamilies       #-}++module Language.While.Hoare where++import Control.Monad.Writer++import           Language.While.Syntax++import           Language.Expression.Prop+import           Language.Expression.Pretty+import           Language.Verification+import           Language.Verification.Conditions++type WhileProp l = Prop (WhileExpr l)++data PropAnn l a = PropAnn (WhileProp l Bool) a++type AnnCommand l a = Command l (PropAnn l a)++instance (Pretty l, Pretty a) => Pretty (PropAnn l a) where+  prettysPrec _ (PropAnn prop ann) = prettysPrec 10 prop . showString " , " . prettysPrec 10 ann++type MonadGen l = WriterT [WhileProp l Bool] Maybe++--------------------------------------------------------------------------------+--  Exposed Functions+--------------------------------------------------------------------------------++-- | Generate verification conditions to prove that the given Hoare partial+-- correctness triple holds.+generateVCs+  :: (VerifiableVar (WhileVar l))+  => WhileProp l Bool -> WhileProp l Bool -> AnnCommand l a+  -> Maybe [WhileProp l Bool]+generateVCs precond postcond cmd =+  execWriterT $ generateVCs' (precond, postcond, cmd)+++generateVCs'+  :: (VerifiableVar (WhileVar l))+  => Triplet (HFree WhileOp) (WhileVar l) (AnnCommand l a) -> MonadGen l ()+generateVCs' (precond, postcond, cmd) = case cmd of+  CAnn (PropAnn prop _) command ->+    generateVCs' ((prop *&& precond), postcond, command)++  c@(CSeq _ _) -> do+    s <- lift (splitSeq c)+    void $ sequenceVCs generateVCs' (precond, postcond, s)++  CSkip -> skipVCs (precond, postcond, ())++  CAssign loc e ->+    assignVCs (precond, postcond, (Assignment (WhileVar loc) e))++  CIf cond c1 c2 ->+    void $ ifVCs generateVCs' expr (precond, postcond, (cond, c1, c2))++  CWhile cond (CAnn (PropAnn invariant _) body) ->+    whileVCs generateVCs'+      expr+      invariant+      (precond, postcond, (cond, body))++  -- If this falls through, the command is not sufficiently annotated+  _ -> mzero++--------------------------------------------------------------------------------+--  Internal+--------------------------------------------------------------------------------++-- | Split the command into all the top-level sequenced commands, interspersed+-- with annotations. Returns 'Nothing' if the command's sequences are not+-- sufficiently annotated.+splitSeq :: AnnCommand l a -> Maybe (AnnSeq (HFree WhileOp) (WhileVar l) (AnnCommand l a))+splitSeq = \case+  CSeq c1 (CAnn (PropAnn midcond _) c2) ->+    do a1 <- splitSeq c1+       a2 <- splitSeq c2+       return $ Annotation a1 midcond a2+  CSeq c1 (CAssign loc e) ->+    do a1 <- splitSeq c1+       a1 `joinAnnSeq` JustAssign [Assignment (WhileVar loc) e]+  CSeq c1 c2 ->+    do a1 <- splitSeq c1+       a2 <- splitSeq c2+       a1 `joinAnnSeq` a2+  CAssign loc e -> return $ JustAssign [Assignment (WhileVar loc) e]+  c -> return $ CmdAssign c []
+ Language/While/Hoare/Prover.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase       #-}+{-# LANGUAGE TypeFamilies     #-}++module Language.While.Hoare.Prover where++import           Data.SBV                (SBV)++import           Language.Expression.Prop+import           Language.Verification++import           Language.While.Hoare+import           Language.While.Syntax+++checkPartialHoare+  :: (VerifiableVar (WhileVar l), VarSym (WhileVar l) ~ SBV)+  => WhileProp l Bool+  -> WhileProp l Bool+  -> AnnCommand l a+  -> Query (WhileVar l) (SBV Bool)+checkPartialHoare precond postcond cmd =+  do vcs <- case generateVCs precond postcond cmd of+              Just x  -> return x+              Nothing -> fail "Command not sufficiently annotated"++     let bigVC = foldr (*&&) (plit True) vcs++     evalPropSimple bigVC++provePartialHoare+  :: (VerifiableVar (WhileVar l), VarSym (WhileVar l) ~ SBV, VarEnv (WhileVar l) ~ ())+  => WhileProp l Bool+  -> WhileProp l Bool+  -> AnnCommand l a+  -> IO (Either (VerifierError (WhileVar l)) Bool)+provePartialHoare precond postcond cmd =+  runVerifier . flip query () $ checkPartialHoare precond postcond cmd
+ Language/While/Syntax.hs view
@@ -0,0 +1,285 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE DeriveDataTypeable    #-}+{-# LANGUAGE DeriveFunctor         #-}+{-# LANGUAGE DeriveTraversable     #-} +{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms       #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeSynonymInstances  #-}+++module Language.While.Syntax where++import           Data.String                     (IsString (..))+import           Data.Typeable                   ((:~:) (..))++import           Data.SBV+import           Data.SBV.Internals              (SBV (..))+import           Data.Vinyl                      (Rec (RNil))+import           Data.Vinyl.Curry++import           Control.Lens                    hiding ((...), (.>))+import           Control.Monad.State+import           Data.Map                        (Map)+import qualified Data.Map                        as Map++import           Language.Expression+import           Language.Expression.GeneralOp+import           Language.Expression.Pretty+import           Language.Expression.Util+import           Language.Verification++--------------------------------------------------------------------------------+--  Operator kind+--------------------------------------------------------------------------------++data WhileOpKind as r where+  OpLit                        :: AlgReal -> WhileOpKind '[]      AlgReal+  OpAdd, OpSub, OpMul          :: WhileOpKind '[AlgReal, AlgReal] AlgReal+  OpEq, OpLT, OpLE, OpGT, OpGE :: WhileOpKind '[AlgReal, AlgReal] Bool+  OpAnd, OpOr                  :: WhileOpKind '[Bool   , Bool]    Bool+  OpNot                        :: WhileOpKind '[Bool]             Bool+++instance EvalOpAt Identity WhileOpKind where++  evalMany = \case+    OpLit x -> \_ -> pure x++    OpAdd -> runcurryA' (+)+    OpSub -> runcurryA' (-)+    OpMul -> runcurryA' (*)++    OpEq -> runcurryA' (==)+    OpLT -> runcurryA' (<)+    OpLE -> runcurryA' (<=)+    OpGT -> runcurryA' (>)+    OpGE -> runcurryA' (>=)++    OpAnd -> runcurryA' (&&)+    OpOr  -> runcurryA' (||)++    OpNot -> runcurryA' not++instance EvalOpAt SBV WhileOpKind where+  evalMany = \case+    OpLit x -> \_ -> literal x++    OpAdd -> runcurry (+)+    OpSub -> runcurry (-)+    OpMul -> runcurry (*)++    OpEq -> runcurry (.==)+    OpLT -> runcurry (.<)+    OpLE -> runcurry (.<=)+    OpGT -> runcurry (.>)+    OpGE -> runcurry (.>=)++    OpAnd -> runcurry (&&&)+    OpOr -> runcurry (|||)++    OpNot -> runcurry bnot++-- instance EqOpMany WhileOpKind where+--   liftEqMany (OpLit x) (OpLit y) _ = \_ _ -> x == y+--   liftEqMany OpAdd OpAdd k = k+--   liftEqMany OpSub OpSub k = k+--   liftEqMany OpMul OpMul k = k+--   liftEqMany OpEq  OpEq  k = k+--   liftEqMany OpLT  OpLT  k = k+--   liftEqMany OpLE  OpLE  k = k+--   liftEqMany OpGT  OpGT  k = k+--   liftEqMany OpGE  OpGE  k = k+--   liftEqMany OpAnd OpAnd k = k+--   liftEqMany OpOr  OpOr  k = k+--   liftEqMany OpNot OpNot k = k+--   liftEqMany _ _ _ = \_ _ -> False++prettys1Binop ::+  (Pretty1 t) =>+  Int -> String -> (Int -> t a -> t b -> ShowS)+prettys1Binop prec opStr = \p x y ->+  showParen (p > prec) $ prettys1Prec (prec + 1) x+                       . showString opStr+                       . prettys1Prec (prec + 1) y++instance PrettyOp WhileOpKind where+  prettysPrecOp = flip $ \case+    OpAdd -> runcurry . prettys1Binop 5 " + "+    OpSub -> runcurry . prettys1Binop 5 " - "+    OpMul -> runcurry . prettys1Binop 6 " * "++    OpEq -> runcurry . prettys1Binop 4 " = "++    OpLT -> runcurry . prettys1Binop 4 " < "+    OpLE -> runcurry . prettys1Binop 4 " <= "+    OpGT -> runcurry . prettys1Binop 4 " > "+    OpGE -> runcurry . prettys1Binop 4 " >= "++    OpNot ->+      \p ->+        runcurry $ \x -> showParen (p > 8) $ showString "! " . prettys1Prec 9 x+    OpAnd -> runcurry . prettys1Binop 3 " && "+    OpOr -> runcurry . prettys1Binop 2 " || "++    OpLit x -> \_ _ -> shows x++--------------------------------------------------------------------------------+--  Operators+--------------------------------------------------------------------------------++type WhileOp = GeneralOp WhileOpKind++--------------------------------------------------------------------------------+--  Variables+--------------------------------------------------------------------------------++data WhileVar l a where+  WhileVar :: l -> WhileVar l AlgReal++instance Pretty l => Pretty1 (WhileVar l) where+  pretty1 (WhileVar l) = pretty l++instance VerifiableVar (WhileVar String) where+  type VarKey (WhileVar String) = String+  type VarSym (WhileVar String) = SBV+  type VarEnv (WhileVar String) = ()+ +  symForVar (WhileVar x) = const $ symbolic x+  varKey (WhileVar x) = x+  eqVarTypes (WhileVar _) (WhileVar _) = Just Refl+  castVarSym (WhileVar _) (SBV x) = Just (SBV x)++--------------------------------------------------------------------------------+--  Expressions+--------------------------------------------------------------------------------++type WhileExpr l = HFree WhileOp (WhileVar l)++instance Num (WhileExpr l AlgReal) where+  fromInteger x = HWrap (Op (OpLit (fromInteger x)) RNil)++  (+) = HWrap ... rcurry (Op OpAdd)+  (*) = HWrap ... rcurry (Op OpMul)+  (-) = HWrap ... rcurry (Op OpSub)+  abs = error "can't take abs of expressions"+  signum = error "can't take signum of expressions"++instance IsString s => IsString (WhileExpr s AlgReal) where+  fromString = HPure . WhileVar . fromString++--------------------------------------------------------------------------------+--  Commands+--------------------------------------------------------------------------------++data Command l a+  = CAnn a (Command l a)+  | CSeq (Command l a) (Command l a)+  | CSkip+  | CAssign l (WhileExpr l AlgReal)+  | CIf (WhileExpr l Bool) (Command l a) (Command l a)+  | CWhile (WhileExpr l Bool) (Command l a)++instance (Pretty l, Pretty a) => Pretty (Command l a) where+  prettysPrec p = \case+    CAnn ann c ->+      showParen (p > 10) $ showString "{ "+                         . prettys ann+                         . showString " }\n"+                         . prettys c+    CSeq c1 c2 ->+      showParen (p > 10) $ prettys c1 . showString ";\n" . prettys c2+    CSkip -> showString "()"+    CAssign v e ->+      showParen (p > 10) $ prettys v . showString " := " . prettys e+    CIf cond c1 c2 ->+      showParen (p > 10) $ showString "if "+                         . prettysPrec 11 cond+                         . showString " then\n"+                         . prettysPrec 11 c1+                         . showString "\nelse\n"+                         . prettysPrec 11 c2+    CWhile cond body ->+      showParen (p > 10) $ showString "while "+                         . prettysPrec 11 cond+                         . showString " do\n"+                         . prettysPrec 11 body++--------------------------------------------------------------------------------+--  Running Commands+--------------------------------------------------------------------------------++data StepResult a+  = Terminated+  | Failed+  | Progress a+  deriving (Functor)++evalWhileExpr+  :: (Applicative f)+  => (forall x. WhileVar l x -> f x)+  -> WhileExpr l a -> f a+evalWhileExpr f+  = fmap runIdentity+  . hfoldTraverse (fmap Identity . f)++oneStep+  :: (Ord l)+  => Command l a+  -> State (Map l AlgReal) (StepResult (Command l a))+oneStep = \case+  CAnn ann c -> fmap (CAnn ann) <$> oneStep c++  CSeq c1 c2 ->+    do s <- oneStep c1+       case s of+         Terminated -> return (Progress c2)+         Failed -> return Failed+         Progress c1' -> return (Progress (c1' `CSeq` c2))++  CSkip -> return Terminated++  CAssign loc expr ->+    do env <- get+       if Map.member loc env then+         case evalWhileExpr (lookupVar env) expr of+           Just val ->+             do at loc .= Just val+                return Terminated+           Nothing -> return Failed+         -- Can't assign a memory location that doesn't exist+         else return Failed++  CIf cond c1 c2 ->+    do env <- get+       case evalWhileExpr (lookupVar env) cond of+         Just True -> return (Progress c1)+         Just False -> return (Progress c2)+         _ -> return Failed++  CWhile cond body ->+    do env <- get+       case evalWhileExpr (lookupVar env) cond of+         Just True -> return (Progress (body `CSeq` (CWhile cond body)))+         Just False -> return Terminated+         _ -> return Failed+++runCommand :: (Ord l) => Command l a -> State (Map l AlgReal) Bool+runCommand command =+  do s <- oneStep command+     case s of+       Terminated -> return True+       Failed -> return False+       Progress command' -> runCommand command'++--------------------------------------------------------------------------------+--  Combinators+--------------------------------------------------------------------------------++lookupVar :: (Ord l) => Map l AlgReal -> WhileVar l a -> Maybe a+lookupVar env (WhileVar s) = Map.lookup s env
+ Language/While/Syntax/Sugar.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE OverloadedStrings #-}++module Language.While.Syntax.Sugar where++import           Data.SBV                        (AlgReal)++import           Data.Vinyl.Curry++import           Language.Expression+import           Language.Expression.GeneralOp+import           Language.Expression.Util+import           Language.While.Hoare+import           Language.While.Syntax++infix 1 .=.+infixr 0 \\+infix 3 ^^^+infix 8 .<+infix 8 .<=+infix 8 .>+infix 8 .>=+infixr 7 .&&+infixr 6 .||++(.=.) :: l -> WhileExpr l AlgReal -> Command l a+(.=.) = CAssign++(\\) :: Command l a -> Command l a -> Command l a+(\\) = CSeq++(^^^) :: WhileProp l Bool -> AnnCommand l () -> AnnCommand l ()+prop ^^^ command = CAnn (PropAnn prop ()) command++(.==) :: WhileExpr l AlgReal -> WhileExpr l AlgReal -> WhileExpr l Bool+(.==) = HWrap ... rcurry (Op OpEq)++(.<) :: WhileExpr l AlgReal -> WhileExpr l AlgReal -> WhileExpr l Bool+(.<) = HWrap ... rcurry (Op OpLT)++(.>) :: WhileExpr l AlgReal -> WhileExpr l AlgReal -> WhileExpr l Bool+(.>) = HWrap ... rcurry (Op OpGT)++(.<=) :: WhileExpr l AlgReal -> WhileExpr l AlgReal -> WhileExpr l Bool+(.<=) = HWrap ... rcurry (Op OpLE)++(.>=) :: WhileExpr l AlgReal -> WhileExpr l AlgReal -> WhileExpr l Bool+(.>=) = HWrap ... rcurry (Op OpGE)++(.&&) :: WhileExpr l Bool -> WhileExpr l Bool -> WhileExpr l Bool+(.&&) = HWrap ... rcurry (Op OpAnd)++(.||) :: WhileExpr l Bool -> WhileExpr l Bool -> WhileExpr l Bool+(.||) = HWrap ... rcurry (Op OpOr)++wenot :: WhileExpr l Bool -> WhileExpr l Bool+wenot = HWrap . rcurry (Op OpNot)
+ Language/While/Test.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE OverloadedStrings #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}++module Language.While.Test where++import           Language.Expression.Pretty+import           Language.Expression.Prop+import           Language.Verification++import           Language.While.Hoare+import           Language.While.Hoare.Prover+import           Language.While.Syntax+import           Language.While.Syntax.Sugar++import           Data.SBV                    (SMTConfig (..), defaultSMTCfg)++testCommandAnn :: Command String (PropAnn String ())+testCommandAnn =+  "Q" .=. 0   \\ (expr ("R" .== "x") *&& expr ("Q" .== 0)) ^^^+  CWhile ("Y" .<= "R")+  ((expr ("x" .== ("R" + "Y" * "Q"))) ^^^+   (  "R" .=. "R" - "Y"+   \\ "Q" .=. "Q" + 1+   ))++testPrecond :: WhileProp String Bool+testPrecond = expr ("R" .== "x")++testPostcond :: WhileProp String Bool+testPostcond =+  expr ("x" .== ("R" + "Y" * "Q")) *&&+  expr ("R" .< "Y")++testConfig :: SMTConfig+testConfig = defaultSMTCfg { verbose = False }++testVcs :: Maybe [WhileProp String Bool]+testVcs = generateVCs testPrecond testPostcond testCommandAnn++test :: IO (Either (VerifierError (WhileVar String)) Bool)+test = runVerifierWith testConfig $ flip query () $+  checkPartialHoare testPrecond testPostcond testCommandAnn
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ verifiable-expressions.cabal view
@@ -0,0 +1,49 @@+-- This file has been generated from package.yaml by hpack version 0.20.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: dff4863bb87472933f3daa41b069320c635d14714d46d778116a53854de0e95c++name:           verifiable-expressions+version:        0.4.0+synopsis:       An intermediate language for Hoare logic style verification.+description:    A typed intermediate language for Hoare logic style verification. It defines the intermediate language and combinators to interact it.+category:       Language+author:         Bradley Hardy+maintainer:     bch29@cam.ac.uk+license:        Apache-2.0+license-file:   LICENSE+build-type:     Simple+cabal-version:  >= 1.10++library+  ghc-options: -Wall+  build-depends:+      base >=4.9 && <5+    , containers >=0.5.7 && <0.6+    , lens >=4.16.1 && <5+    , mtl >=2.0 && <3+    , sbv >=7.0 && <8+    , transformers >=0.5 && <0.6+    , union >=0.1.1 && <0.2+    , vinyl >=0.8.1 && <0.9+  exposed-modules:+      Language.Expression+      Language.Expression.Example+      Language.Expression.Choice+      Language.Expression.Scope+      Language.Expression.GeneralOp+      Language.Expression.Prop+      Language.Expression.Pretty+      Language.Expression.Util+      Language.Verification+      Language.Verification.Conditions+      Language.Verification.Core+      Language.While.Hoare+      Language.While.Hoare.Prover+      Language.While.Syntax+      Language.While.Syntax.Sugar+      Language.While.Test+  other-modules:+      Paths_verifiable_expressions+  default-language: Haskell2010