packages feed

datafix 0.0.0.2 → 0.0.1.0

raw patch · 40 files changed

+741/−915 lines, 40 filesdep −Globdep ~basedep ~cabal-toolkitdep ~containerssetup-changednew-component:exe:firstfollow-examplePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: Glob

Dependency ranges changed: base, cabal-toolkit, containers, pomaps, primitive

API changes (from Hackage documentation)

- Datafix.Explicit: DFP :: !(Node -> LiftedFunc (Domain m) m) -> !(Node -> ChangeDetector (Domain m)) -> DataFlowProblem m
- Datafix.Explicit: [dfpDetectChange] :: DataFlowProblem m -> !(Node -> ChangeDetector (Domain m))
- Datafix.Explicit: [dfpTransfer] :: DataFlowProblem m -> !(Node -> LiftedFunc (Domain m) m)
- Datafix.Explicit: data DataFlowProblem m
- Datafix.ProblemBuilder: buildProblem :: forall m. MonadDependency m => Denotation (Domain m) -> (Node, Node, DataFlowProblem m)
- Datafix.ProblemBuilder: data ProblemBuilder m a
- Datafix.ProblemBuilder: instance Datafix.Explicit.MonadDependency m => Datafix.Denotational.MonadDatafix (Datafix.ProblemBuilder.ProblemBuilder m)
- Datafix.ProblemBuilder: instance GHC.Base.Applicative (Datafix.ProblemBuilder.ProblemBuilder m)
- Datafix.ProblemBuilder: instance GHC.Base.Functor (Datafix.ProblemBuilder.ProblemBuilder m)
- Datafix.ProblemBuilder: instance GHC.Base.Monad (Datafix.ProblemBuilder.ProblemBuilder m)
+ Datafix: arrowsAxiom :: Arrows (ParamTypes func) (ReturnType func) :~: func
+ Datafix: class Currying as b
+ Datafix: currys :: Currying as b => (Products as -> b) -> Arrows as b
+ Datafix: data ConsMap0 :: (Function k l -> *) -> Function k (Function [l] [l] -> *) -> *
+ Datafix: data ConsMap1 :: (Function k l -> *) -> k -> Function [l] [l] -> *
+ Datafix: data Constant0 :: Function a (Function b a -> *) -> *
+ Datafix: data Constant1 :: * -> Function b a -> *
+ Datafix: data Function :: * -> * -> *
+ Datafix: type Arrows (as :: [*]) (r :: *) = Foldr (->) r as
+ Datafix: type family All (p :: k -> Constraint) (as :: [k]) :: Constraint
+ Datafix: uncurrys :: Currying as b => Arrows as b -> Products as -> b
+ Datafix.Common: (<!) :: forall f arr. Currying (ParamTypes arr) (ReturnType arr) => Functor f => f arr -> Products (ParamTypes arr) -> f (ReturnType arr)
+ Datafix.Common: --
+ Datafix.Common: -- If you can't guarantee monotonicity, try to pull non-monotone
+ Datafix.Common: -- When this reduces to a function, then all functions of this domain are
+ Datafix.Common: -- arguments into <tt>Node</tt>s.
+ Datafix.Common: -- assumed to be monotone wrt. the (at least) partial order of all
+ Datafix.Common: -- occuring types!
+ Datafix.Common: -- | The abstract domain in which nodes of the data-flow graph are denoted.
+ Datafix.Common: evalAt :: forall f arr. Currying (ParamTypes arr) (ReturnType arr) => Functor f => f arr -> Products (ParamTypes arr) -> f (ReturnType arr)
+ Datafix.Denotational: -- instantiated to some <tt>MonadDependency</tt>, if you choose to go
+ Datafix.Denotational: -- through <tt>FrameworkBuilder</tt>.
+ Datafix.Denotational: -- | The monad in which data dependencies are expressed. Can and will be
+ Datafix.Explicit: DFF :: !Node -> LiftedFunc (Domain m) m -> !Node -> ChangeDetector (Domain m) -> DataFlowFramework m
+ Datafix.Explicit: [dffDetectChange] :: DataFlowFramework m -> !Node -> ChangeDetector (Domain m)
+ Datafix.Explicit: [dffTransfer] :: DataFlowFramework m -> !Node -> LiftedFunc (Domain m) m
+ Datafix.Explicit: data DataFlowFramework m
+ Datafix.FrameworkBuilder: buildFramework :: forall m a. MonadDependency m => (forall md. (MonadDatafix md, DepM md ~ m) => md a) -> (a, Node, DataFlowFramework m)
+ Datafix.FrameworkBuilder: data FrameworkBuilder m a
+ Datafix.FrameworkBuilder: instance Datafix.Explicit.MonadDependency m => Datafix.Denotational.MonadDatafix (Datafix.FrameworkBuilder.FrameworkBuilder m)
+ Datafix.FrameworkBuilder: instance GHC.Base.Applicative (Datafix.FrameworkBuilder.FrameworkBuilder m)
+ Datafix.FrameworkBuilder: instance GHC.Base.Functor (Datafix.FrameworkBuilder.FrameworkBuilder m)
+ Datafix.FrameworkBuilder: instance GHC.Base.Monad (Datafix.FrameworkBuilder.FrameworkBuilder m)
+ Datafix.MonoMap: --
+ Datafix.MonoMap: -- <tt>k</tt>.
+ Datafix.MonoMap: -- The default implementation delegates to <a>POMap</a>.
+ Datafix.MonoMap: -- | The particular ordered map implementation to use for the key type
+ Datafix.Utils.Constraints: type family Forall (p :: k -> Constraint) :: Constraint
+ Datafix.Utils.TypeLevel: type family Apply (t :: Function k l -> *) (u :: k) :: l
- Datafix.Denotational: type Denotation dom = forall m. (MonadDatafix m, dom ~ Domain (DepM m)) => m (LiftedFunc dom (DepM m))
+ Datafix.Denotational: type Denotation domain func = forall m. (MonadDatafix m, domain ~ Domain (DepM m)) => m (LiftedFunc func (DepM m))
- Datafix.MonoMap: empty :: (MonoMapKey k, (MonoMap k v ~ POMap k v)) => MonoMap k v
+ Datafix.MonoMap: empty :: (MonoMapKey k, MonoMap k v ~ POMap k v) => MonoMap k v
- Datafix.MonoMap: singleton :: (MonoMapKey k, (MonoMap k v ~ POMap k v)) => k -> v -> MonoMap k v
+ Datafix.MonoMap: singleton :: (MonoMapKey k, MonoMap k v ~ POMap k v) => k -> v -> MonoMap k v
- Datafix.Utils.Constraints: newtype a (:-) b
+ Datafix.Utils.Constraints: newtype a :- b
- Datafix.Worklist: AbortAfter :: Int -> (AbortionFunction domain) -> IterationBound domain
+ Datafix.Worklist: AbortAfter :: Int -> AbortionFunction domain -> IterationBound domain
- Datafix.Worklist: evalDenotation :: Datafixable domain => Denotation domain -> IterationBound domain -> domain
+ Datafix.Worklist: evalDenotation :: forall domain func. Datafixable domain => Forall (Currying (ParamTypes func)) => Denotation domain func -> IterationBound domain -> func
- Datafix.Worklist: solveProblem :: forall domain graph. GraphRef graph => Datafixable domain => DataFlowProblem (DependencyM graph domain) -> Density graph -> IterationBound domain -> Node -> domain
+ Datafix.Worklist: solveProblem :: forall domain graph a. GraphRef graph => Datafixable domain => DataFlowFramework (DependencyM graph domain) -> Density graph -> IterationBound domain -> DependencyM graph domain a -> a
- Datafix.Worklist.Denotational: evalDenotation :: Datafixable domain => Denotation domain -> IterationBound domain -> domain
+ Datafix.Worklist.Denotational: evalDenotation :: forall domain func. Datafixable domain => Forall (Currying (ParamTypes func)) => Denotation domain func -> IterationBound domain -> func
- Datafix.Worklist.Graph: Diff :: !(IntArgsMonoSet a) -> !(IntArgsMonoSet a) -> Diff a
+ Datafix.Worklist.Graph: Diff :: !IntArgsMonoSet a -> !IntArgsMonoSet a -> Diff a
- Datafix.Worklist.Graph: PointInfo :: !(Maybe (ReturnType domain)) -> !(IntArgsMonoSet (Products (ParamTypes domain))) -> !(IntArgsMonoSet (Products (ParamTypes domain))) -> !Int -> PointInfo domain
+ Datafix.Worklist.Graph: PointInfo :: !Maybe (ReturnType domain) -> !IntArgsMonoSet (Products (ParamTypes domain)) -> !IntArgsMonoSet (Products (ParamTypes domain)) -> !Int -> PointInfo domain
- Datafix.Worklist.Graph: [added] :: Diff a -> !(IntArgsMonoSet a)
+ Datafix.Worklist.Graph: [added] :: Diff a -> !IntArgsMonoSet a
- Datafix.Worklist.Graph: [references] :: PointInfo domain -> !(IntArgsMonoSet (Products (ParamTypes domain)))
+ Datafix.Worklist.Graph: [references] :: PointInfo domain -> !IntArgsMonoSet (Products (ParamTypes domain))
- Datafix.Worklist.Graph: [referrers] :: PointInfo domain -> !(IntArgsMonoSet (Products (ParamTypes domain)))
+ Datafix.Worklist.Graph: [referrers] :: PointInfo domain -> !IntArgsMonoSet (Products (ParamTypes domain))
- Datafix.Worklist.Graph: [removed] :: Diff a -> !(IntArgsMonoSet a)
+ Datafix.Worklist.Graph: [removed] :: Diff a -> !IntArgsMonoSet a
- Datafix.Worklist.Graph: [value] :: PointInfo domain -> !(Maybe (ReturnType domain))
+ Datafix.Worklist.Graph: [value] :: PointInfo domain -> !Maybe (ReturnType domain)
- Datafix.Worklist.Internal: AbortAfter :: Int -> (AbortionFunction domain) -> IterationBound domain
+ Datafix.Worklist.Internal: AbortAfter :: Int -> AbortionFunction domain -> IterationBound domain
- Datafix.Worklist.Internal: DM :: (ReaderT (Env graph domain) IO a) -> DependencyM graph domain a
+ Datafix.Worklist.Internal: DM :: ReaderT (Env graph domain) IO a -> DependencyM graph domain a
- Datafix.Worklist.Internal: Env :: !(DataFlowProblem (DependencyM graph domain)) -> !(IterationBound domain) -> !(IntArgsMonoSet (Products (ParamTypes domain))) -> !(graph domain) -> !(IORef (IntArgsMonoSet (Products (ParamTypes domain)))) -> !(IORef (IntArgsMonoSet (Products (ParamTypes domain)))) -> Env graph domain
+ Datafix.Worklist.Internal: Env :: !DataFlowFramework (DependencyM graph domain) -> !IterationBound domain -> !IntArgsMonoSet (Products (ParamTypes domain)) -> !graph domain -> !IORef (IntArgsMonoSet (Products (ParamTypes domain))) -> !IORef (IntArgsMonoSet (Products (ParamTypes domain))) -> Env graph domain
- Datafix.Worklist.Internal: [callStack] :: Env graph domain -> !(IntArgsMonoSet (Products (ParamTypes domain)))
+ Datafix.Worklist.Internal: [callStack] :: Env graph domain -> !IntArgsMonoSet (Products (ParamTypes domain))
- Datafix.Worklist.Internal: [graph] :: Env graph domain -> !(graph domain)
+ Datafix.Worklist.Internal: [graph] :: Env graph domain -> !graph domain
- Datafix.Worklist.Internal: [iterationBound] :: Env graph domain -> !(IterationBound domain)
+ Datafix.Worklist.Internal: [iterationBound] :: Env graph domain -> !IterationBound domain
- Datafix.Worklist.Internal: [problem] :: Env graph domain -> !(DataFlowProblem (DependencyM graph domain))
+ Datafix.Worklist.Internal: [problem] :: Env graph domain -> !DataFlowFramework (DependencyM graph domain)
- Datafix.Worklist.Internal: [referencedPoints] :: Env graph domain -> !(IORef (IntArgsMonoSet (Products (ParamTypes domain))))
+ Datafix.Worklist.Internal: [referencedPoints] :: Env graph domain -> !IORef (IntArgsMonoSet (Products (ParamTypes domain)))
- Datafix.Worklist.Internal: [unstable] :: Env graph domain -> !(IORef (IntArgsMonoSet (Products (ParamTypes domain))))
+ Datafix.Worklist.Internal: [unstable] :: Env graph domain -> !IORef (IntArgsMonoSet (Products (ParamTypes domain)))
- Datafix.Worklist.Internal: initialEnv :: IntArgsMonoSet (Products (ParamTypes domain)) -> DataFlowProblem (DependencyM graph domain) -> IterationBound domain -> IO (graph domain) -> IO (Env graph domain)
+ Datafix.Worklist.Internal: initialEnv :: IntArgsMonoSet (Products (ParamTypes domain)) -> DataFlowFramework (DependencyM graph domain) -> IterationBound domain -> IO (graph domain) -> IO (Env graph domain)
- Datafix.Worklist.Internal: solveProblem :: forall domain graph. GraphRef graph => Datafixable domain => DataFlowProblem (DependencyM graph domain) -> Density graph -> IterationBound domain -> Node -> domain
+ Datafix.Worklist.Internal: solveProblem :: forall domain graph a. GraphRef graph => Datafixable domain => DataFlowFramework (DependencyM graph domain) -> Density graph -> IterationBound domain -> DependencyM graph domain a -> a

Files

Setup.hs view
@@ -1,2 +1,10 @@+import           Distribution.Extra.Doctest+import           Distribution.Simple import           Distribution.Simple.Toolkit-main = defaultMainWithBuildInfo++main :: IO ()+main = defaultMainWithHooks simpleUserHooksWithBuildInfo+  { buildHook = \pkg lbi hooks flags -> do+      generateBuildModule "doctests" flags pkg lbi+      buildHook simpleUserHooks pkg lbi hooks flags+  }
bench/Main.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -fno-warn-orphans #-}  import           Algebra.Lattice@@ -6,9 +7,6 @@ import           Criterion import           Criterion.Main import           Datafix-import           Datafix.Worklist               (Density (..),-                                                 IterationBound (..),-                                                 solveProblem) import           Datafix.Worklist.Graph         (GraphRef) import           Numeric.Natural @@ -36,7 +34,7 @@   rnf = seqExpr  fixSum :: GraphRef graph => (Node -> Density graph) -> Int -> Natural-fixSum density n = solveProblem sumProblem (density (Node n)) NeverAbort (Node n)+fixSum density n = solveProblem sumFramework (density (Node n)) NeverAbort (dependOn @(DependencyM _ Natural) (Node n))  main :: IO () main = defaultMain
datafix.cabal view
@@ -1,5 +1,5 @@ name:                datafix-version:             0.0.0.2+version:             0.0.1.0 synopsis:            Fixing data-flow problems description:         Fixing data-flow problems in expression trees.                      This should be useful if you want to write optimizations@@ -13,14 +13,16 @@ license-file:        LICENSE author:              Sebastian Graf maintainer:          sgraf1337@gmail.com-copyright:           © 2018 Sebastian Graf+copyright:           © 2017-2020 Sebastian Graf homepage:            https://github.com/sgraf812/datafix bug-reports:         https://github.com/sgraf812/datafix/issues  category:            Compiler build-type:          Custom stability:           alpha (experimental)-cabal-version:       1.24+-- We have autogen-modules, so we need Cabal 2.0+cabal-version:       2.0+tested-with:         GHC==8.8.1, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2  extra-source-files:   CHANGELOG.md@@ -36,15 +38,11 @@   type:     git   location: https://github.com/sgraf812/datafix -flag no-lattices-  description: Don't depend on the lattices package.-  default: False- custom-setup   setup-depends:       base     , Cabal-    -- let cabal-toolkit choose the right Cabal and base versions+    , cabal-doctest >= 1 && < 1.1     , cabal-toolkit >= 0.0.4  library@@ -57,7 +55,7 @@                      Datafix.Explicit                      Datafix.MonoMap                      Datafix.NodeAllocator-                     Datafix.ProblemBuilder+                     Datafix.FrameworkBuilder                      Datafix.Tutorial                      Datafix.Utils.Constraints                      Datafix.Utils.TypeLevel@@ -73,19 +71,16 @@                      Datafix.IntArgsMonoMap                      Datafix.IntArgsMonoSet   build-depends:     base >= 4.8 && < 5-                   , containers >= 0.5 && < 0.6+                   , containers >= 0.5 && < 0.7                    , transformers < 0.6                    -- Just Data.Vector.Mutable, which has been there for ages                    , vector < 0.13                    -- Data.Primitive.Array.sizeofArray was introduced in 0.6.2.0-                   , primitive >= 0.6.2.0 && < 0.7-                   -- has not reached the first major version, so quite unstable-                   , pomaps >= 0.0.0.2 && < 0.0.1.0-  if !flag(no-lattices)-    build-depends:   lattices < 2-  if flag(no-lattices)-    hs-source-dirs:  lattices-    exposed-modules: Algebra.Lattice+                   , primitive >= 0.6.2.0 && < 0.8+                   -- Prior to 0.2, pomaps used to offer a flag to compile without+                   -- lattices that confuses CI+                   , pomaps >= 0.2 && < 0.3+                   , lattices  test-suite tests   type:              exitcode-stdio-1.0@@ -102,16 +97,17 @@                      Analyses.Syntax.MkCoreHelpers                      Analyses.Syntax.MkCoreFromFile                      Analyses.Templates.LetDn+                     SetRecurrences.FirstFollow                      Fib                      Fac                      Mutual                      Critical                      Trivial                      StrAnal+                     FirstFollow   build-depends:     base >= 4.8 && < 5-                   -- let cabal-toolkit choose the Cabal version                    , Cabal-                   , cabal-toolkit == 0.0.4+                   , cabal-toolkit >= 0.0.4                    , tasty >= 0.11                    , tasty-hunit >= 0.9                    , tasty-smallcheck >= 0.8@@ -125,10 +121,7 @@                    , filepath                    , turtle                    , text-  if !flag(no-lattices)-    build-depends:   lattices < 2-  if flag(no-lattices)-    build-depends:   pomaps >= 0.0.0.2 && < 0.0.1.0+                   , lattices < 2  test-suite doctests   type:              exitcode-stdio-1.0@@ -138,9 +131,10 @@   main-is:           doctest.hs   build-depends:     base >= 4.8 && < 5                    , doctest >=0.10-                   , Glob >= 0.7                    , QuickCheck >= 2.5                    , datafix+  other-modules:     Build_doctests+  autogen-modules:   Build_doctests  benchmark benchmarks   type:              exitcode-stdio-1.0@@ -148,8 +142,7 @@   ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N   hs-source-dirs:    bench examples   main-is:           Main.hs-  other-modules:     Sum-                     Analyses.AdHocStrAnal+  other-modules:     Analyses.AdHocStrAnal                      Analyses.StrAnal                      Analyses.StrAnal.Analysis                      Analyses.StrAnal.Arity@@ -158,23 +151,30 @@                      Analyses.Syntax.MkCoreHelpers                      Analyses.Syntax.MkCoreFromFile                      Analyses.Templates.LetDn+                     Sum   build-depends:     base >= 4.8 && < 5-                   -- let cabal-toolkit choose the Cabal version                    , Cabal-                   , cabal-toolkit == 0.0.4+                   , cabal-toolkit >= 0.0.4                    , criterion >= 1.1                    , deepseq                    , containers                    , primitive                    , transformers < 0.6-                   , datafix                   +                   , datafix                    , ghc                    , ghc-paths                    , directory                    , filepath                    , turtle                    , text-  if !flag(no-lattices)-    build-depends:   lattices < 2-  if flag(no-lattices)-    build-depends:   pomaps >= 0.0.0.2 && < 0.0.1.0+                   , lattices < 2++executable firstfollow-example+  default-language:  Haskell2010+  hs-source-dirs:    examples+  main-is:           SetRecurrences/FirstFollow/Main.hs+  ghc-options:       -Wall -threaded -rtsopts -with-rtsopts=-N+  other-modules:     SetRecurrences.FirstFollow+  build-depends:     base+                   , containers+                   , datafix
examples/Analyses/StrAnal/Analysis.hs view
@@ -1,12 +1,13 @@ {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-} -- This is so that the specialisation of transferFunctionAlg gets inlined. {-# OPTIONS_GHC -funfolding-creation-threshold=999999 #-} --{-# OPTIONS_GHC -ddump-simpl -ddump-to-file -dsuppress-all #-}  -- | This module defines a strictness analysis in the style of GHC's -- projection-based backwards analysis by defining a 'transferFunctionAlg'--- that is passed on to @Analyses.Templates.LetDn.'buildProblem'@,--- yielding a 'DataFlowProblem' to be solved by @Datafix.'solveProblem'@.+-- that is passed on to @Analyses.Templates.LetDn.'buildFramework'@,+-- yielding a 'DataFlowFramework' to be solved by @Datafix.'solveProblem'@. module Analyses.StrAnal.Analysis (analyse) where  import           Algebra.Lattice@@ -24,7 +25,7 @@ import           VarEnv  analyse :: CoreExpr -> StrLattice-analyse expr = evalDenotation (buildDenotation transferFunctionAlg expr) NeverAbort (0 :: Arity)+analyse expr = evalDenotation @(Arity -> StrLattice) (buildDenotation transferFunctionAlg expr) NeverAbort (0 :: Arity)  applyWhen :: Bool -> (a -> a) -> a -> a applyWhen True f  = f@@ -32,7 +33,7 @@  -- | This specifies the strictness as a 'TransferAlgebra'. Note the absence -- of any recursion! That's all abstracted into--- @Analyses.Tempaltes.LetDn.'buildProblem'@, so that this function definition+-- @Analyses.Tempaltes.LetDn.'buildFramework'@, so that this function definition -- is completely compositional: It is only concerned with peeling off a single -- layer of the 'CoreExprF' and interpret that in terms of the -- transfer function over the @Arity -> StrLattice@ 'Domain'.
examples/Analyses/Templates/LetDn.hs view
@@ -12,8 +12,8 @@ -- sites depending on incoming argument strictness. -- -- The idea is that users of this module only need to provide a--- 'TransferAlgebra' for 'buildProblem' to get a specification for the desired--- data-flow problem. Remarkably, 'buildProblem' completely abstracts away+-- 'TransferAlgebra' for 'buildFramework' to get a specification for the desired+-- data-flow problem. Remarkably, 'buildFramework' completely abstracts away -- recursive bindings: The passed 'TransferAlgebra' is non-recursive and thus -- doesn't need to do any allocation of 'Node's or calls to 'dependOn'. -- As a result, 'TransferAlgebra's operate in a clean @forall m. Monad m@@@ -58,7 +58,7 @@ type TF m = LiftedFunc (Domain m) m  -- | Given a 'TransferAlgebra', this function takes care of building a--- 'DataFlowProblem' for 'CoreExpr's.+-- 'DataFlowFramework' for 'CoreExpr's. -- It allocates 'Node's and ties knots for recursive bindings -- through calls to 'dependOn'. These are then hidden in a 'VarEnv' -- and passed on to the 'TransferAlgebra', which can stay completely@@ -66,12 +66,12 @@ -- -- It returns the root 'Node', denoting the passed expression, and the maximum -- allocated 'Node', which allows to configure 'solveProblem' with a dense--- 'GraphRef'. The final return value is the 'DataFlowProblem' reflecting+-- 'GraphRef'. The final return value is the 'DataFlowFramework' reflecting -- the analysis specified by the 'TransferAlgebra' applied to the given -- 'CoreExpr'. -- -- Continuing the recursion schemes analogy from 'TransferAlgebra',--- 'buildProblem' is a recursion scheme. Applying it to a 'TransferAlgebra'+-- 'buildFramework' is a recursion scheme. Applying it to a 'TransferAlgebra' -- yields a catamorphism. It is special in that recursive let-bindings -- lead to non-structural recursion, so termination isn't obvious and -- demands some confidence in domain theory by the programmer.@@ -81,7 +81,7 @@   => Currying (ParamTypes domain) (ReturnType domain -> ReturnType domain -> Bool)   => TransferAlgebra domain   -> CoreExpr-  -> Denotation domain+  -> Denotation domain domain buildDenotation = buildDenotation'  -- This brings in the scope the existentially quantified 'MonadDatafix'. Too
examples/Fac.hs view
@@ -7,8 +7,8 @@ import           Datafix import           Numeric.Natural -facProblem :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowProblem m-facProblem = DFP transfer (const (eqChangeDetector @(Domain m)))+facFramework :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowFramework m+facFramework = DFF transfer (const (eqChangeDetector @(Domain m)))   where     transfer :: Node -> LiftedFunc Natural m     transfer (Node 0) = return 1
examples/Fib.hs view
@@ -7,8 +7,8 @@ import           Datafix import           Numeric.Natural -fibProblem :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowProblem m-fibProblem = DFP transfer (const (eqChangeDetector @(Domain m)))+fibFramework :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowFramework m+fibFramework = DFF transfer (const (eqChangeDetector @(Domain m)))   where     transfer :: Node -> LiftedFunc Natural m     transfer (Node 0) = return 0
examples/Mutual.hs view
@@ -7,7 +7,7 @@ import           Datafix import           Numeric.Natural --- | A 'DataFlowProblem' with two nodes, mutually depending on another, like+-- | A 'DataFlowFramework' with two nodes, mutually depending on another, like -- -- @ --    a = b + 1@@ -16,8 +16,8 @@ -- -- After a few bounces, this will reach a stable state where the first node -- has value 11 and the other has value 10.-mutualRecursiveProblem :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowProblem m-mutualRecursiveProblem = DFP transfer (const (eqChangeDetector @(Domain m)))+mutualRecursiveFramework :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowFramework m+mutualRecursiveFramework = DFF transfer (const (eqChangeDetector @(Domain m)))   where     transfer :: Node -> LiftedFunc Natural m     transfer (Node 0) = do
+ examples/SetRecurrences/FirstFollow.hs view
@@ -0,0 +1,201 @@+{-# LANGUAGE AllowAmbiguousTypes   #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes            #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeApplications      #-}+{-# OPTIONS_GHC -fexpose-all-unfoldings #-}++module SetRecurrences.FirstFollow+  ( V (..)+  , WithEOF (..)+  , Grammar (..)+  , mkGrammar+  , augmentGrammar+  , first+  , follow+  , dyck+  , llsll+  , emptyL+  , leftrec+  ) where++import           Prelude hiding (words)++import           Datafix++import           Control.Applicative+import           Control.Monad+import           Data.Bifunctor (second)+import           Data.Functor.Identity+import           Data.List (unfoldr)+import           Data.Map (Map)+import qualified Data.Map as Map+import           Data.Maybe (fromMaybe)+import           Data.Set (Set)+import qualified Data.Set as Set++data V t nt+  = T t+  | NT nt+  deriving (Eq, Ord, Show)++eitherV :: (t -> r) -> (nt -> r) -> V t nt -> r+eitherV l _ (T t)   = l t+eitherV _ r (NT nt) = r nt++data WithEOF a+  = EOF+  | NoEOF a+  deriving (Eq, Ord, Show)++instance {-# OVERLAPPING #-} Show [WithEOF Char] where+  show = show . map f+    where+      f EOF       = '#'+      f (NoEOF c) = c++data Grammar t nt+  = G+  { terminals :: Set t+  , nonterminals :: Set nt+  , productions :: Map nt (Set [V t nt])+  , start :: nt+  }++mkGrammar :: (Ord v) => [v] -> [v] -> [(v, [v])] -> v -> Grammar v v+mkGrammar ts nts ps s+  = G+  { terminals    = Set.fromList ts+  , nonterminals = Set.fromList nts+  , productions  = Map.fromListWith Set.union (map (second (Set.singleton . map mkV)) ps)+  , start        = s+  }+  where+    mkV v+      | v `elem` ts  = T v+      | v `elem` nts = NT v+      | otherwise  = error "not part of vocabulary"++augmentGrammar :: (Ord t, Ord nt) => nt -> Grammar t nt -> Grammar t nt+augmentGrammar s' gr+  = G+  { terminals    = terminals gr+  , nonterminals = Set.insert s' (nonterminals gr)+  , productions  = Map.insert s' (Set.singleton [NT (start gr)]) $ productions gr+  , start        = s'+  }++epsilon :: [t]+epsilon = []++kconcat :: Int -> [a] -> [a] -> [a]+kconcat k pref suf = take k (pref ++ suf)++pointwise2 :: Ord c => (a -> b -> c) -> Set a -> Set b -> Set c+pointwise2 f as bs = Set.fromList (liftA2 f (Set.toList as) (Set.toList bs))++-- |+-- NB: A Monad here is strictly more performant than Applicative here, because+-- we can exit early. On the other this means we have this really adhoc fold over+subst :: (Monad m, Ord t) => Int -> (nt -> m (Set [t])) -> [V t nt] -> m (Set [t])+subst k lkup = go (Set.singleton epsilon)+  where+    go prefs [] = pure prefs+    go prefs (v:vs) = do+      suffs <- eitherV (pure . Set.singleton . (:[])) lkup v+      let words = pointwise2 (kconcat k) prefs suffs+      if any ((< k) . length) words+        then go words vs+        else pure words++first :: forall t nt . (Ord t, Ord nt, Datafixable (Set [t])) => Int -> Grammar t nt -> [V t nt] -> Set [t]+first k gr = runIdentity . subst k (Identity . (firstSolutions k gr Map.!))++firstSolutions :: forall t nt . (Ord t, Ord nt, Datafixable (Set [t])) => Int -> Grammar t nt -> Map nt (Set [t])+firstSolutions k gr = evalDenotation @(Set [t]) @(Map nt (Set [t])) plan NeverAbort+  where+    plan :: forall m . (MonadDatafix m, Domain (DepM m) ~ Set [t]) => m (DepM m (Map nt (Set [t])))+    plan = sequence <$> build Map.empty (Set.toList (nonterminals gr))+    build :: forall m . (MonadDatafix m, Domain (DepM m) ~ Set [t]) => Map nt (DepM m (Set [t])) -> [nt] -> m (Map nt (DepM m (Set [t])))+    build env []       = pure env+    build env (nt:nts) = datafixEq $ \self -> do+      env' <- build (Map.insert nt self env) nts+      let rhss = Set.toList (fromMaybe Set.empty (Map.lookup nt (productions gr)))+      let iter = Set.unions <$> mapM (subst k (env' Map.!)) rhss+      pure (env', iter)++-- | Assumes the given grammar is augmented+follow :: forall t nt . (Ord t, Ord nt, Datafixable (Set [WithEOF t])) => Int -> Grammar t nt -> nt -> Set [WithEOF t]+follow k gr = (evalDenotation @(Set [WithEOF t]) plan NeverAbort Map.!)+  where+    prods :: [(nt, [V t nt])]+    prods =+      [ (nt, rhs)+      | (nt, rhss) <- Map.toList (productions gr)+      , rhs <- Set.toList rhss+      ]+    firsts = firstSolutions k gr+    initialEnv :: forall m . Monad m => Map nt (m (Set [WithEOF t]))+    initialEnv = Map.singleton (start gr) (pure (Set.singleton (replicate k EOF)))+    plan :: forall m . (MonadDatafix m, Domain (DepM m) ~ Set [WithEOF t]) => m (DepM m (Map nt (Set [WithEOF t])))+    plan = sequence <$> build initialEnv (Set.toList (Set.delete (start gr) (nonterminals gr)))+    build :: forall m . (MonadDatafix m, Domain (DepM m) ~ Set [WithEOF t]) => Map nt (DepM m (Set [WithEOF t])) -> [nt] -> m (Map nt (DepM m (Set [WithEOF t])))+    build env []       = pure env+    build env (nt:nts) = datafixEq $ \self -> do+      env' <- build (Map.insert nt self env) nts+      let occs = flip concatMap prods $ \(parent, rhs) -> flip unfoldr rhs $ \rest ->+            case dropWhile (/= NT nt) rest of+              [] -> Nothing+              (_:follows) -> Just ((parent, follows), follows)++      let iter = fmap Set.unions $ forM occs $ \(parent, follows) -> do+            let prefs = Set.map (map NoEOF) $ runIdentity $ subst k (Identity . (firsts Map.!)) follows+            let (short, long) = Set.partition ((< k) . length) prefs+            if null short+              then pure prefs+              else Set.union long . pointwise2 (kconcat k) prefs <$> (env' Map.! parent)++      pure (env', iter)++dyck :: Grammar Char Char+dyck = augmentGrammar 'O' $ mkGrammar+  "()"+  "S"+  [ ('S', "")+  , ('S', "(S)S")+  ]+  'S'++llsll :: Grammar Char Char+llsll = augmentGrammar 'O' $ mkGrammar+  "ab"+  "ZA"+  [ ('Z', "aAab")+  , ('Z', "bAb")+  , ('A', "a")+  , ('A', "")+  ]+  'Z'++emptyL :: Grammar Char Char+emptyL = augmentGrammar 'O' $ mkGrammar+  ""+  "ABC"+  [ ('A', "BC")+  , ('B', "CA")+  , ('C', "A")+  ]+  'A'++leftrec :: Grammar Char Char+leftrec = augmentGrammar 'O' $ mkGrammar+  "abc"+  "SA"+  [ ('S', "Aa")+  , ('A', "Sb")+  , ('A', "c")+  ]+  'S'
+ examples/SetRecurrences/FirstFollow/Main.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE FlexibleContexts      #-}++import           System.Environment+import           Text.Printf+import           SetRecurrences.FirstFollow++main :: IO ()+main = do+  (k:_) <- map read <$> getArgs+  let uncurry3 f (x,y,z) = f x y z+  let analyse name gr (s :: Char) = do+        printf "%s:\n" name+        printf "  first_%d(%s): %s\n" k (show s) (show $ first k gr [NT s])+        printf "  follow_%d(%s): %s\n" k (show s) (show $ follow k gr s)+        putStrLn ""+  mapM_ (uncurry3 analyse)+    [ ("Dyck", dyck, 'S')+    , ("LL(1), not SLL(k)", llsll, 'A')+    , ("empty", emptyL, 'A')+    , ("left recursive", leftrec, 'S')+    ]+
examples/Sum.hs view
@@ -7,8 +7,8 @@ import           Datafix import           Numeric.Natural -sumProblem :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowProblem m-sumProblem = DFP transfer (const (eqChangeDetector @(Domain m)))+sumFramework :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowFramework m+sumFramework = DFF transfer (const (eqChangeDetector @(Domain m)))   where     transfer :: Node -> LiftedFunc Natural m     transfer (Node 0) = return 0
exprs/lambda.hs view
@@ -1,6 +1,6 @@-{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-module Expr where+module Lambda ( expr ) where  -- From Mark: marku@cs.waikato.ac.nz [Nov 2001] -- This program contrasts the cost of direct and@@ -38,20 +38,20 @@ --              and about 7 times more memory. -- -import           System.Environment+import System.Environment -import           Control.Monad.Trans.State.Strict-import           Data.Functor.Identity+import Control.Monad.Trans.State.Strict+import Data.Functor.Identity+import Control.Monad (replicateM_) -------------------------------------------------------------------------- A directly recursive Eval, with explicit environment-------------------------------------------------------------------------- A trivial monad so that we can use monad syntax.-newtype Id a = Id (Identity a)-    deriving (Applicative, Functor, Monad)+expr :: Id Term+expr = simpleEval [] (App sum0 (Con 1)) -instance Show a => Show (Id a) where-    show (Id i) = show (runIdentity i)+------------------------------------------------------------+-- Data structures+------------------------------------------------------------+--instance Show (a -> b) where+--    show f = "<function>"   data Term@@ -67,6 +67,18 @@     deriving (Eq,Read,Show)  type Env = [(String,Term)]+++----------------------------------------------------------------------+-- Evaluate a term+----------------------------------------------------------------------+ev :: Term -> IO (Env,Term)+ev t =+    do  let (t2, env) = runState (traverseTerm t :: State Env Term) []+        putStrLn (pp t2 ++ "  " ++ ppenv env)+        return (env,t2)++ ----------------------------------------------------------------- -- This class extends Monad to have the standard features -- we expect while evaluating/manipulating expressions.@@ -84,178 +96,168 @@  instance EvalEnvMonad (State Env) where     incr = return ()-    traverseTerm = undefined -- eval+    traverseTerm = eval     lookupVar v = do-        env <- get-        return $ lookup2 env+          env <- get+          return $ lookup2 env         where-        lookup2 env = maybe (error ("undefined var: " ++ v)) id (lookup v env)+          lookup2 env = maybe (error ("undefined var: " ++ v)) id (lookup v env)     currEnv = get     withEnv tmp m = return (evalState m tmp) -expr :: IO ()-expr = do { mainSimple ; mainMonad }-  where-    mainSimple =-        do  args <- getArgs-            if null args-            then putStrLn "Args: number-to-sum-up-to"-            else putStrLn (show (simpleEval [] (App sum0 (Con (read(head args))))))--    mainMonad =-        do  args <- getArgs-            if null args-            then putStrLn "Args: number-to-sum-up-to"-            else (ev (App sum0 (Con (read(head args))))) >> return ()-+traverseCon :: (EvalEnvMonad m) => Term -> m Int+traverseCon t =+    do t' <- traverseTerm t+       case t' of+           Con c -> return c+           _ -> error ("Not a Con: " ++ show t') -    -------------------------------------------------------------    -- Data structures-    -------------------------------------------------------------    --instance Show (a -> b) where-    --    show f = "<function>"+eval :: (EvalEnvMonad m) => Term -> m Term+eval (Var x)   =+    do e <- currEnv+       t <- lookupVar x+       traverseTerm t+eval (Add u v) =+    do {u' <- traverseCon u;+        v' <- traverseCon v;+        return (Con (u'+v'))}+eval (Thunk t e) =+    withEnv e (traverseTerm t)+eval f@(Lam x b) =+    do  env <- currEnv+        return (Thunk f env)  -- return a closure!+eval (App u v) =+    do {u' <- traverseTerm u;+        -- call-by-name, so we do not evaluate the argument v+        apply u' v+       }+eval (IfZero c a b) =+    do {val <- traverseTerm c;+        if val == Con 0+           then traverseTerm a+           else traverseTerm b}+eval (Con i)   = return (Con i)+eval (Incr)    = incr >> return (Con 0) -    -----------------------------------------------------------------------    -- Evaluate a term-    -----------------------------------------------------------------------    ev :: Term -> IO (Env,Term)-    ev t =-        do  let (t2, env) = runState (traverseTerm t :: State Env Term) []-            putStrLn (pp t2 ++ "  " ++ ppenv env)-            return (env,t2)+--apply :: Term -> Term -> StateMonad2 Term+apply (Thunk (Lam x b) e) a =+    do  orig <- currEnv+        withEnv e (pushVar x (Thunk a orig) (traverseTerm b))+apply a b         = error ("bad application: " ++ pp a +++                              "  [ " ++ pp b ++ " ].")    -    eval :: (EvalEnvMonad m) => Term -> m Term-    eval (Var x)   =-        do e <- currEnv-           t <- lookupVar x-           traverseTerm t-    eval (Add u v) =-        do {Con u' <- traverseTerm u;-            Con v' <- traverseTerm v;-            return (Con (u'+v'))}-    eval (Thunk t e) =-        withEnv e (traverseTerm t)-    eval f@(Lam x b) =-        do  env <- currEnv-            return (Thunk f env)  -- return a closure!-    eval (App u v) =-        do {u' <- traverseTerm u;-            -- call-by-name, so we do not evaluate the argument v-            apply u' v-        }-    eval (IfZero c a b) =-        do {val <- traverseTerm c;-            if val == Con 0-            then traverseTerm a-            else traverseTerm b}-    eval (Con i)   = return (Con i)-    eval (Incr)    = incr >> return (Con 0)--    --apply :: Term -> Term -> StateMonad2 Term-    apply (Thunk (Lam x b) e) a =-        do  orig <- currEnv-            withEnv e (pushVar x (Thunk a orig) (traverseTerm b))-    apply a b         = fail ("bad application: " ++ pp a ++-                                "  [ " ++ pp b ++ " ].")-+----------------------------------------------------------------------+-- A directly recursive Eval, with explicit environment+----------------------------------------------------------------------+-- A trivial monad so that we can use monad syntax.+newtype Id a = Id (Identity a)+    deriving (Applicative, Functor, Monad) +instance Show a => Show (Id a) where+    show (Id i) = show (runIdentity i) +simpleEvalCon :: Env -> Term -> Id Int+simpleEvalCon env e =+    do e' <- simpleEval env e+       case e' of+           Con c -> return c+           _ -> error ("Not a Con: " ++ show e') -    simpleEval :: Env -> Term -> Id Term-    simpleEval env (Var v) =-        simpleEval env (maybe (error ("undefined var: " ++ v)) id (lookup v env))-    simpleEval env e@(Con _) =-        return e-    simpleEval env e@Incr =-        return (Con 0)-    simpleEval env (Add u v) =-        do {Con u' <- simpleEval env u;-            Con v' <- simpleEval env v;-            return (Con (u' + v'))}-        where-        addCons (Con a) (Con b) = return (Con (a+b))-        addCons (Con _) b = fail ("type error in second arg of Add: " ++ pp b)-        addCons a (Con _) = fail ("type error in first arg of Add: " ++ pp a)-    simpleEval env f@(Lam x b) =-        return (Thunk f env)  -- return a closure!-    simpleEval env (App u v) =-        do {u' <- simpleEval env u;-            -- call-by-name, so we do not evaluate the argument v-            simpleApply env u' v-        }-    simpleEval env (IfZero c a b) =-        do {val <- simpleEval env c;-            if val == Con 0-            then simpleEval env a-            else simpleEval env b}-    simpleEval env (Thunk t e) =-        simpleEval e t+simpleEval :: Env -> Term -> Id Term+simpleEval env (Var v) =+    simpleEval env (maybe (error ("undefined var: " ++ v)) id (lookup v env))+simpleEval env e@(Con _) =+    return e+simpleEval env e@Incr =+    return (Con 0)+simpleEval env (Add u v) =+    do {u' <- simpleEvalCon env u;+        v' <- simpleEvalCon env v;+        return (Con (u' + v'))}+    where+    addCons (Con a) (Con b) = return (Con (a+b))+    addCons (Con _) b = error ("type error in second arg of Add: " ++ pp b)+    addCons a (Con _) = error ("type error in first arg of Add: " ++ pp a)+simpleEval env f@(Lam x b) =+    return (Thunk f env)  -- return a closure!+simpleEval env (App u v) =+    do {u' <- simpleEval env u;+        -- call-by-name, so we do not evaluate the argument v+        simpleApply env u' v+       }+simpleEval env (IfZero c a b) =+    do {val <- simpleEval env c;+        if val == Con 0+           then simpleEval env a+           else simpleEval env b}+simpleEval env (Thunk t e) =+    simpleEval e t -    simpleApply :: Env -> Term -> Term -> Id Term-    simpleApply env (Thunk (Lam x b) e) a =-        simpleEval env2 b-        where-        env2 = (x, Thunk a env) : e-    simpleApply env a b         = fail ("bad application: " ++ pp a ++-                                "  [ " ++ pp b ++ " ].")+simpleApply :: Env -> Term -> Term -> Id Term+simpleApply env (Thunk (Lam x b) e) a =+    simpleEval env2 b+    where+    env2 = (x, Thunk a env) : e+simpleApply env a b         = error ("bad application: " ++ pp a +++                              "  [ " ++ pp b ++ " ].") -    -------------------------------------------------------------    -- Utility functions for printing terms and envs.-    -------------------------------------------------------------    ppenv env = "[" ++ concatMap (\(v,t) -> v ++ "=" ++ pp t ++ ", ") env ++ "]"+------------------------------------------------------------+-- Utility functions for printing terms and envs.+------------------------------------------------------------+ppenv env = "[" ++ concatMap (\(v,t) -> v ++ "=" ++ pp t ++ ", ") env ++ "]"  -    pp :: Term -> String-    pp = ppn 0+pp :: Term -> String+pp = ppn 0 -    -- Precedences:-    --   0 = Lam and If (contents never bracketed)-    --   1 = Add-    --   2 = App-    --   3 = atomic and bracketed things-    ppn :: Int -> Term -> String-    ppn _ (Var v) = v-    ppn _ (Con i) = show i-    ppn _ (Incr)  = "INCR"-    ppn n (Lam v t) = bracket n 0 ("@" ++ v ++ ". " ++ ppn (-1) t)-    ppn n (Add a b) = bracket n 1 (ppn 1 a ++ " + " ++ ppn 1 b)-    ppn n (App a b) = bracket n 2 (ppn 2 a ++ " " ++ ppn 2 b)-    ppn n (IfZero c a b) = bracket n 0-        ("IF " ++ ppn 0 c ++ " THEN " ++ ppn 0 a ++ " ELSE " ++ ppn 0 b)-    ppn n (Thunk t e) = bracket n 0 (ppn 3 t ++ "::" ++ ppenv e)+-- Precedences:+--   0 = Lam and If (contents never bracketed)+--   1 = Add+--   2 = App+--   3 = atomic and bracketed things+ppn :: Int -> Term -> String+ppn _ (Var v) = v+ppn _ (Con i) = show i+ppn _ (Incr)  = "INCR"+ppn n (Lam v t) = bracket n 0 ("@" ++ v ++ ". " ++ ppn (-1) t)+ppn n (Add a b) = bracket n 1 (ppn 1 a ++ " + " ++ ppn 1 b)+ppn n (App a b) = bracket n 2 (ppn 2 a ++ " " ++ ppn 2 b)+ppn n (IfZero c a b) = bracket n 0+    ("IF " ++ ppn 0 c ++ " THEN " ++ ppn 0 a ++ " ELSE " ++ ppn 0 b)+ppn n (Thunk t e) = bracket n 0 (ppn 3 t ++ "::" ++ ppenv e) -    bracket outer this t | this <= outer = "(" ++ t ++ ")"-                        | otherwise     = t+bracket outer this t | this <= outer = "(" ++ t ++ ")"+                     | otherwise     = t  -    -------------------------------------------------------------    -- Test Data-    -------------------------------------------------------------    x  = (Var "x")-    y  = (Var "y")-    a1 = (Lam "x" (Add (Var "x") (Con 1)))-    aa = (Lam "x" (Add (Var "x") (Var "x")))+------------------------------------------------------------+-- Test Data+------------------------------------------------------------+x  = (Var "x")+y  = (Var "y")+a1 = (Lam "x" (Add (Var "x") (Con 1)))+aa = (Lam "x" (Add (Var "x") (Var "x"))) -    -- These should all return 1-    iftrue = (IfZero (Con 0) (Con 1) (Con 2))-    iffalse = (IfZero (Con 1) (Con 2) (Con 1))+-- These should all return 1+iftrue = (IfZero (Con 0) (Con 1) (Con 2))+iffalse = (IfZero (Con 1) (Con 2) (Con 1)) -    -- This function sums all the numbers from 0 upto its argument.-    sum0 :: Term-    sum0 = (App fix partialSum0)-    partialSum0 = (Lam "sum"-                    (Lam "n"-                    (IfZero (Var "n")-                        (Con 0)-                        (Add (Var "n") (App (Var "sum") nMinus1)))))-    nMinus1 = (Add (Var "n") (Con (-1)))+-- This function sums all the numbers from 0 upto its argument.+sum0 :: Term+sum0 = (App fix partialSum0)+partialSum0 = (Lam "sum"+                  (Lam "n"+                   (IfZero (Var "n")+                    (Con 0)+                    (Add (Var "n") (App (Var "sum") nMinus1)))))+nMinus1 = (Add (Var "n") (Con (-1))) -    lfxx :: Term-    lfxx = (Lam "x" (App (Var "F") (App (Var "x") (Var "x"))))+lfxx :: Term+lfxx = (Lam "x" (App (Var "F") (App (Var "x") (Var "x")))) -    -- This is the fix point combinator:  Y-    fix :: Term-    fix = (Lam "F" (App lfxx lfxx))+-- This is the fix point combinator:  Y+fix :: Term+fix = (Lam "F" (App lfxx lfxx))
− lattices/Algebra/Lattice.hs
@@ -1,477 +0,0 @@-{-# LANGUAGE CPP                #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric      #-}-{-# LANGUAGE FlexibleInstances  #-}-{-# LANGUAGE Safe               #-}-#if __GLASGOW_HASKELL__ >= 707 && __GLASGOW_HASKELL__ < 709-{-# OPTIONS_GHC -fno-warn-amp #-}-#endif-------------------------------------------------------------------------------- |--- Module      :  Algebra.Lattice--- Copyright   :  (C) 2010-2015 Maximilian Bolingbroke--- License     :  BSD-3-Clause (see the file LICENSE)------ Maintainer  :  Oleg Grenrus <oleg.grenrus@iki.fi>------ In mathematics, a lattice is a partially ordered set in which every--- two elements have a unique supremum (also called a least upper bound--- or @join@) and a unique infimum (also called a greatest lower bound or--- @meet@).------ In this module lattices are defined using 'meet' and 'join' operators,--- as it's constructive one.---------------------------------------------------------------------------------module Algebra.Lattice (-    -- * Unbounded lattices-    JoinSemiLattice(..), MeetSemiLattice(..), Lattice,-    joinLeq, meetLeq,--    -- * Bounded lattices-    BoundedJoinSemiLattice(..), BoundedMeetSemiLattice(..), BoundedLattice,-    joins, meets,-    fromBool,--    -- * Monoid wrappers-    Meet(..), Join(..),--    -- * Fixed points of chains in lattices-    lfp, lfpFrom, unsafeLfp,-    gfp, gfpFrom, unsafeGfp,-  ) where--import qualified Algebra.PartialOrd    as PO--import           Control.Monad.Zip     (MonadZip (..))-import           Data.Data             (Data, Typeable)-import           Data.Proxy            (Proxy (..))-import           Data.Semigroup        (All (..), Any (..), Endo (..),-                                        Semigroup (..))-import           Data.Void             (Void)-import           GHC.Generics          (Generic)--import qualified Data.IntMap           as IM-import qualified Data.IntSet           as IS-import qualified Data.Map              as M-import qualified Data.Set              as S--import           Control.Applicative   (Const (..))-import           Data.Functor.Identity (Identity (..))--infixr 6 /\ -- This comment needed because of CPP-infixr 5 \/---- | A algebraic structure with element joins: <http://en.wikipedia.org/wiki/Semilattice>------ > Associativity: x \/ (y \/ z) == (x \/ y) \/ z--- > Commutativity: x \/ y == y \/ x--- > Idempotency:   x \/ x == x-class JoinSemiLattice a where-    (\/) :: a -> a -> a-    (\/) = join--    join :: a -> a -> a-    join = (\/)--#if __GLASGOW_HASKELL__ >= 707-    {-# MINIMAL (\/) | join #-}-#endif-{-# DEPRECATED join "Use '\\/' infix operator" #-}---- | The partial ordering induced by the join-semilattice structure-joinLeq :: (Eq a, JoinSemiLattice a) => a -> a -> Bool-joinLeq x y = (x \/ y) == y---- | A algebraic structure with element meets: <http://en.wikipedia.org/wiki/Semilattice>------ > Associativity: x /\ (y /\ z) == (x /\ y) /\ z--- > Commutativity: x /\ y == y /\ x--- > Idempotency:   x /\ x == x-class MeetSemiLattice a where-    (/\) :: a -> a -> a-    (/\) = meet--    meet :: a -> a -> a-    meet = (/\)--#if __GLASGOW_HASKELL__ >= 707-    {-# MINIMAL (/\) | meet #-}-#endif-{-# DEPRECATED meet "Use '/\\' infix operator" #-}---- | The partial ordering induced by the meet-semilattice structure-meetLeq :: (Eq a, MeetSemiLattice a) => a -> a -> Bool-meetLeq x y = (x /\ y) == x------ | The combination of two semi lattices makes a lattice if the absorption law holds:--- see <http://en.wikipedia.org/wiki/Absorption_law> and <http://en.wikipedia.org/wiki/Lattice_(order)>------ > Absorption: a \/ (a /\ b) == a /\ (a \/ b) == a-class (JoinSemiLattice a, MeetSemiLattice a) => Lattice a where---- | A join-semilattice with some element |bottom| that \/ approaches.------ > Identity: x \/ bottom == x-class JoinSemiLattice a => BoundedJoinSemiLattice a where-    bottom :: a---- | The join of a list of join-semilattice elements-joins :: (BoundedJoinSemiLattice a, Foldable f) => f a -> a-joins = getJoin . foldMap Join---- | A meet-semilattice with some element |top| that /\ approaches.------ > Identity: x /\ top == x-class MeetSemiLattice a => BoundedMeetSemiLattice a where-    top :: a---- | The meet of a list of meet-semilattice elements-meets :: (BoundedMeetSemiLattice a, Foldable f) => f a -> a-meets = getMeet . foldMap Meet---- | Lattices with both bounds-class (Lattice a, BoundedJoinSemiLattice a, BoundedMeetSemiLattice a) => BoundedLattice a where---- | 'True' to 'top' and 'False' to 'bottom'-fromBool :: BoundedLattice a => Bool -> a-fromBool True  = top-fromBool False = bottom------- Sets-----instance Ord a => JoinSemiLattice (S.Set a) where-    (\/) = S.union--instance Ord a => MeetSemiLattice (S.Set a) where-    (/\) = S.intersection--instance Ord a => Lattice (S.Set a) where--instance Ord a => BoundedJoinSemiLattice (S.Set a) where-    bottom = S.empty------- IntSets-----instance JoinSemiLattice IS.IntSet where-    (\/) = IS.union--instance MeetSemiLattice IS.IntSet where-    (/\) = IS.intersection--instance Lattice IS.IntSet--instance BoundedJoinSemiLattice IS.IntSet where-    bottom = IS.empty------- Maps-----instance (Ord k, JoinSemiLattice v) => JoinSemiLattice (M.Map k v) where-    (\/) = M.unionWith (\/)--instance (Ord k, MeetSemiLattice v) => MeetSemiLattice (M.Map k v) where-    (/\) = M.intersectionWith (/\)--instance (Ord k, Lattice v) => Lattice (M.Map k v) where--instance (Ord k, JoinSemiLattice v) => BoundedJoinSemiLattice (M.Map k v) where-    bottom = M.empty------- IntMaps-----instance JoinSemiLattice v => JoinSemiLattice (IM.IntMap v) where-    (\/) = IM.unionWith (\/)--instance JoinSemiLattice v => BoundedJoinSemiLattice (IM.IntMap v) where-    bottom = IM.empty--instance MeetSemiLattice v => MeetSemiLattice (IM.IntMap v) where-    (/\) = IM.intersectionWith (/\)--instance Lattice v => Lattice (IM.IntMap v)------- Functions-----instance JoinSemiLattice v => JoinSemiLattice (k -> v) where-    f \/ g = \x -> f x \/ g x--instance MeetSemiLattice v => MeetSemiLattice (k -> v) where-    f /\ g = \x -> f x /\ g x--instance Lattice v => Lattice (k -> v) where--instance BoundedJoinSemiLattice v => BoundedJoinSemiLattice (k -> v) where-    bottom = const bottom--instance BoundedMeetSemiLattice v => BoundedMeetSemiLattice (k -> v) where-    top = const top--instance BoundedLattice v => BoundedLattice (k -> v) where---- Unit-instance JoinSemiLattice () where-  _ \/ _ = ()--instance BoundedJoinSemiLattice () where-  bottom = ()--instance MeetSemiLattice () where-  _ /\ _ = ()--instance BoundedMeetSemiLattice () where-  top = ()--instance Lattice () where-instance BoundedLattice () where------- Tuples-----instance (JoinSemiLattice a, JoinSemiLattice b) => JoinSemiLattice (a, b) where-    (x1, y1) \/ (x2, y2) = (x1 \/ x2, y1 \/ y2)--instance (MeetSemiLattice a, MeetSemiLattice b) => MeetSemiLattice (a, b) where-    (x1, y1) /\ (x2, y2) = (x1 /\ x2, y1 /\ y2)--instance (Lattice a, Lattice b) => Lattice (a, b) where--instance (BoundedJoinSemiLattice a, BoundedJoinSemiLattice b) => BoundedJoinSemiLattice (a, b) where-    bottom = (bottom, bottom)--instance (BoundedMeetSemiLattice a, BoundedMeetSemiLattice b) => BoundedMeetSemiLattice (a, b) where-    top = (top, top)--instance (BoundedLattice a, BoundedLattice b) => BoundedLattice (a, b) where------- Bools-----instance JoinSemiLattice Bool where-    (\/) = (||)--instance MeetSemiLattice Bool where-    (/\) = (&&)--instance Lattice Bool where--instance BoundedJoinSemiLattice Bool where-    bottom = False--instance BoundedMeetSemiLattice Bool where-    top = True--instance BoundedLattice Bool where----- Monoids---- | Monoid wrapper for JoinSemiLattice-newtype Join a = Join { getJoin :: a }-  deriving (Eq, Ord, Read, Show, Bounded, Typeable, Data, Generic)--instance JoinSemiLattice a => Semigroup (Join a) where-  Join a <> Join b = Join (a \/ b)--instance BoundedJoinSemiLattice a => Monoid (Join a) where-  mempty = Join bottom-  Join a `mappend` Join b = Join (a \/ b)--instance Functor Join where-  fmap f (Join x) = Join (f x)--instance Applicative Join where-  pure = Join-  Join f <*> Join x = Join (f x)-  _ *> x = x--instance Monad Join where-  return = pure-  Join m >>= f = f m-  (>>) = (*>)--instance MonadZip Join where-  mzip (Join x) (Join y) = Join (x, y)---- | Monoid wrapper for MeetSemiLattice-newtype Meet a = Meet { getMeet :: a }-  deriving (Eq, Ord, Read, Show, Bounded, Typeable, Data, Generic)--instance MeetSemiLattice a => Semigroup (Meet a) where-  Meet a <> Meet b = Meet (a /\ b)--instance BoundedMeetSemiLattice a => Monoid (Meet a) where-  mempty = Meet top-  Meet a `mappend` Meet b = Meet (a /\ b)--instance Functor Meet where-  fmap f (Meet x) = Meet (f x)--instance Applicative Meet where-  pure = Meet-  Meet f <*> Meet x = Meet (f x)-  _ *> x = x--instance Monad Meet where-  return = pure-  Meet m >>= f = f m-  (>>) = (*>)--instance MonadZip Meet where-  mzip (Meet x) (Meet y) = Meet (x, y)---- All-instance JoinSemiLattice All where-  All a \/ All b = All $ a \/ b--instance BoundedJoinSemiLattice All where-  bottom = All False--instance MeetSemiLattice All where-  All a /\ All b = All $ a /\ b--instance BoundedMeetSemiLattice All where-  top = All True--instance Lattice All where-instance BoundedLattice All where---- Any-instance JoinSemiLattice Any where-  Any a \/ Any b = Any $ a \/ b--instance BoundedJoinSemiLattice Any where-  bottom = Any False--instance MeetSemiLattice Any where-  Any a /\ Any b = Any $ a /\ b--instance BoundedMeetSemiLattice Any where-  top = Any True--instance Lattice Any where-instance BoundedLattice Any where---- Endo-instance JoinSemiLattice a => JoinSemiLattice (Endo a) where-  Endo a \/ Endo b = Endo $ a \/ b--instance BoundedJoinSemiLattice a => BoundedJoinSemiLattice (Endo a) where-  bottom = Endo bottom--instance MeetSemiLattice a => MeetSemiLattice (Endo a) where-  Endo a /\ Endo b = Endo $ a /\ b--instance BoundedMeetSemiLattice a => BoundedMeetSemiLattice (Endo a) where-  top = Endo top--instance Lattice a => Lattice (Endo a) where-instance BoundedLattice a => BoundedLattice (Endo a) where---- Proxy-instance JoinSemiLattice (Proxy a) where-  _ \/ _ = Proxy--instance BoundedJoinSemiLattice (Proxy a) where-  bottom = Proxy--instance MeetSemiLattice (Proxy a) where-  _ /\ _ = Proxy--instance BoundedMeetSemiLattice (Proxy a) where-  top = Proxy--instance Lattice (Proxy a) where-instance BoundedLattice (Proxy a) where--#if MIN_VERSION_base(4,8,0)--- Identity-instance JoinSemiLattice a => JoinSemiLattice (Identity a) where-  Identity a \/ Identity b = Identity (a \/ b)--instance BoundedJoinSemiLattice a => BoundedJoinSemiLattice (Identity a) where-  bottom = Identity bottom--instance MeetSemiLattice a => MeetSemiLattice (Identity a) where-  Identity a /\ Identity b = Identity (a /\ b)--instance BoundedMeetSemiLattice a => BoundedMeetSemiLattice (Identity a) where-  top = Identity top--instance Lattice a => Lattice (Identity a) where-instance BoundedLattice a => BoundedLattice (Identity a) where-#endif---- Const-instance JoinSemiLattice a => JoinSemiLattice (Const a b) where-  Const a \/ Const b = Const (a \/ b)--instance BoundedJoinSemiLattice a => BoundedJoinSemiLattice (Const a b) where-  bottom = Const bottom--instance MeetSemiLattice a => MeetSemiLattice (Const a b) where-  Const a /\ Const b = Const (a /\ b)--instance BoundedMeetSemiLattice a => BoundedMeetSemiLattice (Const a b) where-  top = Const top--instance Lattice a => Lattice (Const a b) where-instance BoundedLattice a => BoundedLattice (Const a b) where---- Void-instance JoinSemiLattice Void where-  a \/ _ = a--instance MeetSemiLattice Void where-  a /\ _ = a--instance Lattice Void where---- | Implementation of Kleene fixed-point theorem <http://en.wikipedia.org/wiki/Kleene_fixed-point_theorem>.--- Assumes that the function is monotone and does not check if that is correct.-{-# INLINE unsafeLfp #-}-unsafeLfp :: (Eq a, BoundedJoinSemiLattice a) => (a -> a) -> a-unsafeLfp = PO.unsafeLfpFrom bottom---- | Implementation of Kleene fixed-point theorem <http://en.wikipedia.org/wiki/Kleene_fixed-point_theorem>.--- Forces the function to be monotone.-{-# INLINE lfp #-}-lfp :: (Eq a, BoundedJoinSemiLattice a) => (a -> a) -> a-lfp = lfpFrom bottom---- | Implementation of Kleene fixed-point theorem <http://en.wikipedia.org/wiki/Kleene_fixed-point_theorem>.--- Forces the function to be monotone.-{-# INLINE lfpFrom #-}-lfpFrom :: (Eq a, BoundedJoinSemiLattice a) => a -> (a -> a) -> a-lfpFrom init_x f = PO.unsafeLfpFrom init_x (\x -> f x \/ x)----- | Implementation of Kleene fixed-point theorem <http://en.wikipedia.org/wiki/Kleene_fixed-point_theorem>.--- Assumes that the function is antinone and does not check if that is correct.-{-# INLINE unsafeGfp #-}-unsafeGfp :: (Eq a, BoundedMeetSemiLattice a) => (a -> a) -> a-unsafeGfp = PO.unsafeGfpFrom top---- | Implementation of Kleene fixed-point theorem <http://en.wikipedia.org/wiki/Kleene_fixed-point_theorem>.--- Forces the function to be antinone.-{-# INLINE gfp #-}-gfp :: (Eq a, BoundedMeetSemiLattice a) => (a -> a) -> a-gfp = gfpFrom top---- | Implementation of Kleene fixed-point theorem <http://en.wikipedia.org/wiki/Kleene_fixed-point_theorem>.--- Forces the function to be antinone.-{-# INLINE gfpFrom #-}-gfpFrom :: (Eq a, BoundedMeetSemiLattice a) => a -> (a -> a) -> a-gfpFrom init_x f = PO.unsafeGfpFrom init_x (\x -> f x /\ x)
src/Datafix.hs view
@@ -5,7 +5,7 @@  -- | -- Module      :  Datafix--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable@@ -19,7 +19,7 @@   , module Datafix.Denotational   , module Datafix.Explicit   , module Datafix.NodeAllocator-  , module Datafix.ProblemBuilder+  , module Datafix.FrameworkBuilder   , Datafix.MonoMap.MonoMap   , module Datafix.Utils.TypeLevel   , module Datafix.Worklist@@ -30,6 +30,6 @@ import           Datafix.Explicit import           Datafix.MonoMap import           Datafix.NodeAllocator-import           Datafix.ProblemBuilder-import           Datafix.Utils.TypeLevel+import           Datafix.FrameworkBuilder+import           Datafix.Utils.TypeLevel hiding (Map) import           Datafix.Worklist
src/Datafix/Common.hs view
@@ -11,7 +11,7 @@  -- | -- Module      :  Datafix.Common--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable@@ -26,12 +26,15 @@   , alwaysChangeDetector   , MonadDomain (..)   , Datafixable+  , evalAt+  , (<!)   ) where  import           Algebra.Lattice import           Datafix.MonoMap import           Datafix.Utils.Constraints import           Datafix.Utils.TypeLevel+import           Data.Type.Equality  -- $setup -- >>> :set -XTypeFamilies@@ -169,7 +172,7 @@ --      single line of boiler-plate in most cases, see 'MonoMapKey'. -- --      Note that the monotonicity requirement means we have to pull non-monotone---      arguments in @Domain m@ into the 'Node' portion of the 'DataFlowProblem'.+--      arguments in @Domain m@ into the 'Node' portion of the 'DataFlowFramework'. -- --  3.  For fixed-point iteration to work at all, the values which we iterate --      naturally have to be instances of 'BoundedJoinSemiLattice'.@@ -181,3 +184,26 @@   , MonoMapKey (Products (ParamTypes domain))   , BoundedJoinSemiLattice (ReturnType domain)   )+++evalAt+  :: forall f arr+   . Currying (ParamTypes arr) (ReturnType arr)+  => Functor f+  => f arr+  -> Products (ParamTypes arr)+  -> f (ReturnType arr)+evalAt mfunc args = app <$> mfunc+  where+    app func = uncurrys @(ParamTypes arr) (castWith (sym arrowsAxiom) func) args++(<!)+  :: forall f arr+   . Currying (ParamTypes arr) (ReturnType arr)+  => Functor f+  => f arr+  -> Products (ParamTypes arr)+  -> f (ReturnType arr)+mfunc <! args = app <$> mfunc+  where+    app func = uncurrys @(ParamTypes arr) (castWith (sym arrowsAxiom) func) args
src/Datafix/Denotational.hs view
@@ -9,7 +9,7 @@  -- | -- Module      :  Datafix.Denotational--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable@@ -34,11 +34,11 @@ -- | Builds on an associated 'DepM' that is a 'MonadDomain' (like any -- 'MonadDependency') by providing a way to track dependencies without explicit -- 'Node' management. Essentially, this allows to specify a build plan for a--- 'DataFlowProblem' through calls to 'datafix' in analogy to 'fix' or 'mfix'.+-- 'DataFlowFramework' through calls to 'datafix' in analogy to 'fix' or 'mfix'. class (Monad m, MonadDomain (DepM m)) => MonadDatafix m where   -- | The monad in which data dependencies are expressed.   -- Can and will be instantiated to some 'MonadDependency', if you choose-  -- to go through 'ProblemBuilder'.+  -- to go through 'FrameworkBuilder'.   type DepM m :: * -> *   -- | This is the closest we can get to an actual fixed-point combinator.   --@@ -69,5 +69,5 @@  -- | A denotation of some syntactic entity in a semantic @domain@, built in a -- some 'MonadDatafix' context.-type Denotation dom-  =  forall m. (MonadDatafix m, dom ~ Domain (DepM m)) => m (LiftedFunc dom (DepM m))+type Denotation domain func+  =  forall m. (MonadDatafix m, domain ~ Domain (DepM m)) => m (LiftedFunc func (DepM m))
src/Datafix/Entailments.hs view
@@ -3,7 +3,7 @@  -- | -- Module      :  Datafix.Entailments--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/Explicit.hs view
@@ -9,7 +9,7 @@  -- | -- Module      :  Datafix.Explicit--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable@@ -21,11 +21,11 @@ -- -- Import this module transitively through "Datafix" and get access to -- "Datafix.Worklist" for functions that compute solutions to your--- 'DataFlowProblem's.+-- 'DataFlowFramework's.  module Datafix.Explicit   ( Node (..)-  , DataFlowProblem (..)+  , DataFlowFramework (..)   , MonadDependency (..)   ) where @@ -50,11 +50,11 @@ -- its denoting 'LiftedFunc' and a means to detect when -- the iterated transfer function reached a fixed-point through -- a 'ChangeDetector'.-data DataFlowProblem m-  = DFP-  { dfpTransfer     :: !(Node -> LiftedFunc (Domain m) m)+data DataFlowFramework m+  = DFF+  { dffTransfer     :: !(Node -> LiftedFunc (Domain m) m)   -- ^ A transfer function per each 'Node' of the modeled data-flow problem.-  , dfpDetectChange :: !(Node -> ChangeDetector (Domain m))+  , dffDetectChange :: !(Node -> ChangeDetector (Domain m))   -- ^ A 'ChangeDetector' for each 'Node' of the modeled data-flow problem.   -- In the simplest case, this just delegates to an 'Eq' instance.   }@@ -76,11 +76,11 @@ --   -- sparing the negative n error case -- :} ----- We can construct a description of a 'DataFlowProblem' with this @transferFib@ function:+-- We can construct a description of a 'DataFlowFramework' with this @transferFib@ function: -- -- >>> :{---   dataFlowProblem :: forall m . (MonadDependency m, Domain m ~ Int) => DataFlowProblem m---   dataFlowProblem = DFP transferFib (const (eqChangeDetector @(Domain m)))+--   dataFlowFramework :: forall m . (MonadDependency m, Domain m ~ Int) => DataFlowFramework m+--   dataFlowFramework = DFF transferFib (const (eqChangeDetector @(Domain m))) -- :} -- -- We regard the ordinary @fib@ function a solution to the recurrence modeled by @transferFib@:
+ src/Datafix/FrameworkBuilder.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE FlexibleContexts           #-}+{-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses      #-}+{-# LANGUAGE RankNTypes                 #-}+{-# LANGUAGE ScopedTypeVariables        #-}+{-# LANGUAGE TypeApplications           #-}+{-# LANGUAGE TypeFamilies               #-}++-- |+-- Module      :  Datafix.FrameworkBuilder+-- Copyright   :  (c) Sebastian Graf 2017-2020+-- License     :  ISC+-- Maintainer  :  sgraf1337@gmail.com+-- Portability :  portable+--+-- Builds a 'DataFlowFramework' for a 'Denotation'al formulation in terms of+-- 'MonadDatafix'. Effectively reduces descriptions from "Datafix.Denotational"+-- to ones from "Datafix.Explicit", so that solvers such as "Datafix.Worklist"+-- only have to provide an interpreter for 'MonadDependency'.++module Datafix.FrameworkBuilder+  ( FrameworkBuilder+  , buildFramework+  ) where++import           Data.Primitive.Array+import           Datafix.Common+import           Datafix.Denotational+import           Datafix.Explicit+import           Datafix.NodeAllocator++-- | Constructs a build plan for a 'DataFlowFramework' by tracking allocation of+-- 'Node's mapping to 'ChangeDetector's and transfer functions.+newtype FrameworkBuilder m a+  = FrameworkBuilder { unwrapFB :: NodeAllocator (ChangeDetector (Domain m), LiftedFunc (Domain m) m) a }+  deriving (Functor, Applicative, Monad)++instance MonadDependency m => MonadDatafix (FrameworkBuilder m) where+  type DepM (FrameworkBuilder m) = m+  datafix cd func = FrameworkBuilder $ allocateNode $ \node -> do+    let deref = dependOn @m node+    (ret, transfer) <- unwrapFB (func deref)+    return (ret, (cd, transfer))++-- | @(root, max, dff) = buildFramework builder@ executes the build plan specified+-- by @builder@ and returns the resulting 'DataFlowFramework' @dff@, as well as+-- the @root@ 'Node' denoting the transfer function returned by the+-- 'FrameworkBuilder' action and the @max@imum node of the problem as a proof for+-- its denseness.+buildFramework+  :: forall m a+   . MonadDependency m+  => (forall md . (MonadDatafix md, DepM md ~ m) => md a)+  -> (a, Node, DataFlowFramework m)+buildFramework plan = (a, Node (sizeofArray arr - 1), prob)+  where+    prob = DFF (snd . indexArray arr . unwrapNode) (fst . indexArray arr . unwrapNode)+    (a, arr) = runAllocator $ unwrapFB $ plan @(FrameworkBuilder m)
src/Datafix/IntArgsMonoMap.hs view
@@ -4,7 +4,7 @@  -- | -- Module      :  Datafix.IntArgsMonoMap--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/IntArgsMonoSet.hs view
@@ -4,7 +4,7 @@  -- | -- Module      :  Datafix.IntArgsMonoSet--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/MonoMap.hs view
@@ -1,11 +1,10 @@ {-# LANGUAGE DefaultSignatures      #-} {-# LANGUAGE FlexibleContexts       #-}-{-# LANGUAGE TypeFamilies           #-} {-# LANGUAGE TypeFamilyDependencies #-}  -- | -- Module      :  Datafix.MonoMap--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/NodeAllocator.hs view
@@ -2,7 +2,7 @@  -- | -- Module      :  Datafix.NodeAllocator--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
− src/Datafix/ProblemBuilder.hs
@@ -1,63 +0,0 @@-{-# LANGUAGE FlexibleContexts           #-}-{-# LANGUAGE FlexibleInstances          #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE MultiParamTypeClasses      #-}-{-# LANGUAGE RankNTypes                 #-}-{-# LANGUAGE ScopedTypeVariables        #-}-{-# LANGUAGE TypeApplications           #-}-{-# LANGUAGE TypeFamilies               #-}---- |--- Module      :  Datafix.ProblemBuilder--- Copyright   :  (c) Sebastian Graf 2018--- License     :  ISC--- Maintainer  :  sgraf1337@gmail.com--- Portability :  portable------ Builds a 'DataFlowProblem' for a 'Denotation'al formulation in terms of--- 'MonadDatafix'. Effectively reduces descriptions from "Datafix.Denotational"--- to ones from "Datafix.Explicit", so that solvers such as "Datafix.Worklist"--- only have to provide an interpreter for 'MonadDependency'.--module Datafix.ProblemBuilder-  ( ProblemBuilder-  , buildProblem-  ) where--import           Data.Primitive.Array-import           Datafix.Common-import           Datafix.Denotational-import           Datafix.Entailments-import           Datafix.Explicit-import           Datafix.NodeAllocator-import           Datafix.Utils.Constraints---- | Constructs a build plan for a 'DataFlowProblem' by tracking allocation of--- 'Node's mapping to 'ChangeDetector's and transfer functions.-newtype ProblemBuilder m a-  = ProblemBuilder { unwrapProblemBuilder :: NodeAllocator (ChangeDetector (Domain m), LiftedFunc (Domain m) m) a }-  deriving (Functor, Applicative, Monad)--instance MonadDependency m => MonadDatafix (ProblemBuilder m) where-  type DepM (ProblemBuilder m) = m-  datafix cd func = ProblemBuilder $ allocateNode $ \node -> do-    let deref = dependOn @m node-    (ret, transfer) <- unwrapProblemBuilder (func deref)-    return (ret, (cd, transfer))---- | @(root, max, dfp) = buildProblem builder@ executes the build plan specified--- by @builder@ and returns the resulting 'DataFlowProblem' @dfp@, as well as--- the @root@ 'Node' denoting the transfer function returned by the--- 'ProblemBuilder' action and the @max@imum node of the problem as a proof for--- its denseness.-buildProblem-  :: forall m-   . MonadDependency m-  => Denotation (Domain m)-  -> (Node, Node, DataFlowProblem m)-buildProblem buildDenotation = (root, Node (sizeofArray arr - 1), prob)-  where-    prob = DFP (snd . indexArray arr . unwrapNode) (fst . indexArray arr . unwrapNode)-    (root, arr) = runAllocator $ allocateNode $ \root_ -> do-      denotation <- unwrapProblemBuilder (buildDenotation @(ProblemBuilder m))-      return (root_, (alwaysChangeDetector @(Domain m) \\ cdInst @(Domain m), denotation))
src/Datafix/Tutorial.hs view
@@ -2,7 +2,7 @@  -- | -- Module      :  Datafix.Tutorial--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable@@ -15,8 +15,8 @@ -- [fixed-point iteration](https://en.wikipedia.org/wiki/Fixed-point_iteration). -- -- The need for this library arose when I was combining two analyses--- within GHC for my master's thesis. I recently--- [held a talk](https://cdn.rawgit.com/sgraf812/hiw17/2645b206d3f2b5e6e7c95bc791dfa4bf9cbc8d12/slides.pdf)+-- within GHC for my master's thesis. I+-- [held a talk](https://cdn.jsdelivr.net/gh/sgraf812/hiw17@master/slides.pdf) -- on that topic, feel free to click through if you want to know the details. -- -- You can think of data-flow problems as problems that are solvable by@@ -114,11 +114,11 @@ -- of the transfer function as it is executed! -- -- With our transfer function (which denotes data-flow nodes in the semantics--- of 'Natural's) in place, we can construct a 'DataFlowProblem':+-- of 'Natural's) in place, we can construct a 'DataFlowFramework': -- -- >>> :{---   fibDfp :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowProblem m---   fibDfp = DFP transferFib (const (eqChangeDetector @(Domain m)))+--   fibDff :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowFramework m+--   fibDff = DFF transferFib (const (eqChangeDetector @(Domain m))) -- :} -- -- The 'eqChangeDetector' is important for cyclic dependency graphs and makes@@ -137,7 +137,7 @@ -- -- And now the final incantation of the solver: ----- >>> solveProblem fibDfp Sparse NeverAbort (Node 10)+-- >>> solveProblem fibDff Sparse NeverAbort (dependOn @(DependencyM _ Natural) (Node 10)) -- 55 -- -- This will also execute in \(\mathcal{O}(n)\) space and time, all without@@ -196,8 +196,8 @@ -- :} -- -- >>> :{---   fDfp :: forall m . (MonadDependency m, Domain m ~ Int) => DataFlowProblem m---   fDfp = DFP transferF (const (eqChangeDetector @(Domain m)))+--   fDff :: forall m . (MonadDependency m, Domain m ~ Int) => DataFlowFramework m+--   fDff = DFF transferF (const (eqChangeDetector @(Domain m))) -- :} -- -- Specification of the data-flow problem works the same as for the 'fib'@@ -211,13 +211,13 @@ -- -- Now it's just a matter of calling 'solveProblem' with the right parameters: ----- >>> solveProblem fDfp Sparse NeverAbort (Node 0)+-- >>> solveProblem fDff Sparse NeverAbort (dependOn @(DependencyM _ Int) (Node 0)) -- 0--- >>> solveProblem fDfp Sparse NeverAbort (Node 5)+-- >>> solveProblem fDff Sparse NeverAbort (dependOn @(DependencyM _ Int) (Node 5)) -- 5--- >>> solveProblem fDfp Sparse NeverAbort (Node 42)+-- >>> solveProblem fDff Sparse NeverAbort (dependOn @(DependencyM _ Int) (Node 42)) -- 42--- >>> solveProblem fDfp Sparse NeverAbort (Node (-10))+-- >>> solveProblem fDff Sparse NeverAbort (dependOn @(DependencyM _ Int) (Node (-10))) -- -10 -- -- Note how the /specification/ of the data-flow problem was as unexciting as@@ -264,6 +264,17 @@ -- analyses into their compiler to properly specify the data-flow problems -- in terms of @datafix@ and leave the intricacies of finding a good iteration -- order to this library :)+--+-- = Comparison to Datalog/Soufflé+--+-- In its most declarative form, @datafix@ is an embedded DSL for specifying+-- static analyses. In that regard, it is really similar to+-- [Soufflé](https://souffle-lang.github.io/index.html), only that Soufflé uses+-- an external DSL (a Datalog dialect) to specify the analysis. The resulting+-- compiled executable needs to run in a separate process and gets the facts of+-- the input program encoded in datalog facts. @datafix@ analyses, on the other+-- hand, will be compiled into the host program and don't need an additional+-- communication layer.  module Datafix.Tutorial () where 
src/Datafix/Utils/Constraints.hs view
@@ -13,7 +13,7 @@  -- | -- Module      :  Datafix.Utils.Constraints--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/Utils/GrowableVector.hs view
@@ -1,6 +1,6 @@ -- | -- Module      :  Datafix.GrowableVector--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/Utils/TypeLevel.hs view
@@ -9,7 +9,6 @@ {-# LANGUAGE FlexibleContexts      #-} {-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE GADTs                 #-}-{-# LANGUAGE KindSignatures        #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PolyKinds             #-} {-# LANGUAGE ScopedTypeVariables   #-}@@ -22,7 +21,7 @@  -- | -- Module      :  Datafix.Utils.TypeLevel--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/Worklist.hs view
@@ -1,12 +1,12 @@ -- | -- Module      :  Datafix.Worklist--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable -- -- This module provides the 'Impl.solveProblem' function, which solves the description of a--- 'Datafix.Description.DataFlowProblem' by employing a worklist algorithm.+-- 'Datafix.Description.DataFlowFramework' by employing a worklist algorithm. -- There's also an interpreter for 'Denotation'al problems in the form of -- 'Denotational.evalDenotation'. 
src/Datafix/Worklist/Denotational.hs view
@@ -4,15 +4,16 @@ {-# LANGUAGE RankNTypes            #-} {-# LANGUAGE ScopedTypeVariables   #-} {-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeApplications      #-}  -- | -- Module      :  Datafix.Worklist.Denotational--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable ----- Bridges the "Datafix.Worklist" solver for 'DataFlowProblem's ('solveProblem')+-- Bridges the "Datafix.Worklist" solver for 'DataFlowFramework's ('solveProblem') -- with the "Datafix.Denotational" approach, using 'MonadDatafix' to describe -- a 'Denotation'. @@ -22,26 +23,37 @@  import           Datafix.Common import           Datafix.Denotational-import           Datafix.ProblemBuilder+import           Datafix.Entailments+import           Datafix.Utils.Constraints+import           Datafix.Utils.TypeLevel+import           Datafix.FrameworkBuilder+import qualified Datafix.Worklist.Graph.Dense     as DenseGraph import           Datafix.Worklist.Internal+import           Data.Type.Equality  -- | @evalDenotation denot ib@ returns a value in @domain@ that is described by -- the denotation @denot@. ----- It does so by building up the 'DataFlowProblem' corresponding to @denot@+-- It does so by building up the 'DataFlowFramework' corresponding to @denot@ -- and solving the resulting problem with 'solveProblem', the documentation of -- which describes in detail how to arrive at a stable denotation and what--- the 'IterationBound' @ib@ is for.+-- the 'IterationBound' @ib@, domain ~ Domain (DepM m) is for. evalDenotation-  :: Datafixable domain-  => Denotation domain+  :: forall domain func+   . Datafixable domain+  => Forall (Currying (ParamTypes func))+  => Denotation domain func   -- ^ A build plan for computing the denotation, possibly involving   -- fixed-point iteration factored through calls to 'datafix'.   -> IterationBound domain   -- ^ Whether the solution algorithm should respect a maximum bound on the   -- number of iterations per point. Pass 'NeverAbort' if you don't care.-  -> domain-evalDenotation denot ib = solveProblem prob (Dense max_) ib root-  where-    (root, max_, prob) = buildProblem denot+  -> func+evalDenotation plan ib =+  castWith arrowsAxiom (currys @(ParamTypes func) @(ReturnType func) impl \\ idInst @func)+    where+      impl :: Products (ParamTypes func) -> ReturnType func+      impl args = solveProblem prob (Dense max_) ib (uncurriedDenot args)+      uncurriedDenot = uncurrys @(ParamTypes func) denot \\ lfInst @func @(DependencyM DenseGraph.Ref domain)+      (denot, max_, prob) = buildFramework plan {-# INLINE evalDenotation #-}
src/Datafix/Worklist/Graph.hs view
@@ -5,7 +5,7 @@  -- | -- Module      :  Datafix.Worklist.Graph--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/Worklist/Graph/Dense.hs view
@@ -3,7 +3,7 @@  -- | -- Module      :  Datafix.Worklist.Graph--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/Worklist/Graph/Sparse.hs view
@@ -3,7 +3,7 @@  -- | -- Module      :  Datafix.Worklist.Graph--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable
src/Datafix/Worklist/Internal.hs view
@@ -13,7 +13,7 @@  -- | -- Module      :  Datafix.Worklist.Internal--- Copyright   :  (c) Sebastian Graf 2018+-- Copyright   :  (c) Sebastian Graf 2017-2020 -- License     :  ISC -- Maintainer  :  sgraf1337@gmail.com -- Portability :  portable@@ -30,9 +30,7 @@ import           Control.Monad.Trans.Reader import           Control.Monad.Trans.State.Strict import           Data.IORef-import           Data.Maybe                       (fromMaybe, listToMaybe,-                                                   mapMaybe)-import           Data.Type.Equality+import           Data.Maybe                       (listToMaybe, mapMaybe) import           Datafix.Common import           Datafix.Entailments import           Datafix.Explicit                 hiding (dependOn)@@ -51,7 +49,7 @@ -- | The concrete 'MonadDependency' for this worklist-based solver. -- -- This essentially tracks the current approximation of the solution to the--- 'DataFlowProblem' as mutable state while 'solveProblem' makes sure we will eventually+-- 'DataFlowFramework' as mutable state while 'solveProblem' makes sure we will eventually -- halt with a conservative approximation. newtype DependencyM graph domain a   = DM (ReaderT (Env graph domain) IO a)@@ -60,14 +58,15 @@   --   -- This ultimately leaks badly into the exported interface in 'solveProblem':   -- Since we can't have universally quantified instance contexts (yet!), we can' write-  -- @(forall s. Datafixable domain => (forall s. DataFlowProblem (DependencyM s graph domain)) -> ...@+  -- @(forall s. Datafixable domain => (forall s. DataFlowFramework (DependencyM s graph domain)) -> ...@   -- and have to instead have the isomorphic-  -- @(forall s r. (Datafixable domain => r) -> r) -> (forall s. DataFlowProblem (DependencyM s graph domain)) -> ...@+  -- @(forall s r. (Datafixable domain => r) -> r) -> (forall s. DataFlowFramework (DependencyM s graph domain)) -> ...@   -- and urge all call sites to pass a meaningless 'id' parameter.   --   -- Also, this means more explicit type signatures as we have to make clear to   -- the type-checker that @s@ is universally quantified in everything that-  -- touches it, e.g. @Analyses.StrAnal.LetDn.buildProblem@ from the test suite.+  -- touches it, e.g. @Analyses.StrAnal.LetDn.buildDenotation@ from the test+  -- suite.   --   -- So, bottom line: We resort to 'IO' and 'unsafePerformIO' and promise not to   -- launch missiles. In particular, we don't export 'DM' and also there@@ -77,7 +76,7 @@ -- | The iteration state of 'DependencyM'/'solveProblem'. data Env graph domain   = Env-  { problem          :: !(DataFlowProblem (DependencyM graph domain))+  { problem          :: !(DataFlowFramework (DependencyM graph domain))   -- ^ Constant.   -- The specification of the data-flow problem we ought to solve.   , iterationBound   :: !(IterationBound domain)@@ -100,7 +99,7 @@  initialEnv   :: IntArgsMonoSet (Products (ParamTypes domain))-  -> DataFlowProblem (DependencyM graph domain)+  -> DataFlowFramework (DependencyM graph domain)   -> IterationBound domain   -> IO (graph domain)   -> IO (Env graph domain)@@ -115,7 +114,7 @@ instance Datafixable domain => MonadDomain (DependencyM graph domain) where   type Domain (DependencyM graph domain) = domain --- | This allows us to solve @MonadDependency m => DataFlowProblem m@ descriptions+-- | This allows us to solve @MonadDependency m => DataFlowFramework m@ descriptions -- with 'solveProblem'. instance (Datafixable domain, GraphRef graph) => MonadDependency (DependencyM graph domain) where   dependOn = dependOn @domain @graph@@ -270,9 +269,9 @@ recompute node args = withCall node args $ do   prob <- asks problem   let node' = Node node-  let DM iterate' = uncurrys @dom @(depm cod) (dfpTransfer prob node') args+  let DM iterate' = uncurrys @dom @(depm cod) (dffTransfer prob node') args                   \\ lfInst @domain @depm-  let detectChange' = uncurrys @dom @(cod -> cod -> Bool) (dfpDetectChange prob node') args+  let detectChange' = uncurrys @dom @(cod -> cod -> Bool) (dffDetectChange prob node') args                     \\ cdInst @domain   -- We need to access the graph at three different points in time:   --@@ -435,55 +434,54 @@ work = whileJust_ highestPriorityUnstableNode (uncurry recompute) {-# INLINE work #-} --- | Computes a solution to the described 'DataFlowProblem' by iterating--- transfer functions until a fixed-point is reached.+-- | Computes the (pure) solution of the 'DependencyM' action @act@ specified in+-- the last parameter. @act@ may reference (via 'dependOn') 'Node's of the+-- 'DataFlowFramework' @dff@'s fixed-point, specified as the first parameter. ----- It does do by employing a worklist algorithm, iterating unstable 'Node's--- only.--- 'Node's become unstable when the point of another 'Node' their transfer function--- 'dependOn'ed changed.+-- @dff@'s fixed-point is determined by its transfer functions, and+-- @solveProblem@ will make sure that all (relevant) 'Node's will have reached+-- their fixed-point according to their transfer function before computing the+-- solution for @act@. ----- The sole initially unstable 'Node' is the last parameter, and if your--- 'domain' is function-valued (so the returned 'Arrows' expands to a function),--- then any further parameters specify the exact point in the 'Node's transfer--- function you are interested in.+-- We try to be smart in saving unnecessary iterations of transfer functions by+-- employing a worklist algorithm. For function domains, where each Node denotes+-- a monotone function, each point's dependencies' will be tracked individually. ----- If your problem only has finitely many different 'Node's , consider using--- the 'ProblemBuilder' API (e.g. 'datafix' + 'evalDenotation') for a higher-level API--- that let's you forget about 'Node's and instead let's you focus on building--- more complex data-flow frameworks.+-- Apart from @dff@ and @act@, the 'Density' of the data-flow graph and the+-- 'IterationBound' can be specified. Pass 'Sparse' and 'NeverAbort' when in+-- doubt.+--+-- If your problem only has finitely many different 'Node's , consider using the+-- 'FrameworkBuilder' API (e.g. 'datafix' + 'evalDenotation') for a higher-level+-- API that let's you forget about 'Node's and instead let's you focus on+-- building more complex data-flow frameworks.+--+-- See "Datafix.Tutorial" and the @examples/@ subfolder for examples. solveProblem-  :: forall domain graph+  :: forall domain graph a    . GraphRef graph   => Datafixable domain-  => DataFlowProblem (DependencyM graph domain)-  -- ^ The description of the @DataFlowProblem@ to solve.+  => DataFlowFramework (DependencyM graph domain)+  -- ^ The description of the @DataFlowFramework@.   -> Density graph   -- ^ Describes if the algorithm is free to use a 'Dense', 'Vector'-based   -- graph representation or has to go with a 'Sparse' one based on 'IntMap'.   -> IterationBound domain   -- ^ Whether the solution algorithm should respect a maximum bound on the   -- number of iterations per point. Pass 'NeverAbort' if you don't care.-  -> Node-  -- ^ The @Node@ that is initially assumed to be unstable. This should be-  -- the @Node@ you are interested in, e.g. @Node 42@ if you are interested-  -- in the value of @fib 42@ for a hypothetical @fibProblem@, or the-  -- @Node@ denoting the root expression of your data-flow analysis-  -- you specified via the @DataFlowProblem@.-  -> domain-solveProblem prob density ib (Node node) =-  castWith arrowsAxiom (currys @(ParamTypes domain) @(ReturnType domain) impl \\ idInst @domain)-    where-      impl-        = fromMaybe (error "Broken invariant: The root node has no value")-        . (>>= value)-        . runProblem-      runProblem args = unsafePerformIO $ do-        -- Trust me, I'm an engineer! See the docs of the 'DM' constructor-        -- of 'DependencyM' for why we 'unsafePerformIO'.-        let newGraphRef = case density of-              Sparse               -> SparseGraph.newRef-              Dense (Node maxNode) -> DenseGraph.newRef (maxNode + 1)-        env <- initialEnv (IntArgsMonoSet.singleton node args) prob ib newGraphRef-        runReaderT (work >> withReaderT graph (Graph.lookup node args)) env+  -> DependencyM graph domain a+  -- ^ The action for which we want to compute the solution. May reference+  -- 'Node's from the @DataFlowFramework@. If you just want to know the value of+  -- 'Node' 42, use `dependOn @(DependecyM _ domain) (Node 42)`.+  -> a+solveProblem prob density ib (DM act) = unsafePerformIO $ do+  -- Trust me, I'm an engineer! See the docs of the 'DM' constructor+  -- of 'DependencyM' for why we 'unsafePerformIO'.+  let newGraphRef = case density of+        Sparse               -> SparseGraph.newRef+        Dense (Node maxNode) -> DenseGraph.newRef (maxNode + 1)+  env <- initialEnv IntArgsMonoSet.empty prob ib newGraphRef+  -- Run act once to discover dependencies and an additional time when all+  -- values reached a fixed-point.+  runReaderT (act >> work >> act) env {-# INLINE solveProblem #-}
stack.yaml view
@@ -9,33 +9,14 @@ # resolver: #  name: custom-snapshot #  location: "./custom-snapshot.yaml"-resolver: lts-10.2--# User packages to be built.-# Various formats can be used as shown in the example below.-#-# packages:-# - some-directory-# - https://example.com/foo/bar/baz-0.0.2.tar.gz-# - location:-#    git: https://github.com/commercialhaskell/stack.git-#    commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a-# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a-#   extra-dep: true-#  subdirs:-#  - auto-update-#  - wai-#-# A package marked 'extra-dep: true' will only be built if demanded by a-# non-dependency (i.e. a user package), and its test suites and benchmarks-# will not be run. This is useful for tweaking upstream packages.-packages:-- '.'+resolver: lts-13.30  # Dependency packages to be pulled from upstream that are not in the resolver # (e.g., acme-missiles-0.3) extra-deps:-- pomaps-0.0.0.2+- cabal-toolkit-0.0.7+- cabal-doctest-1.0.8+- pomaps-0.2.0.0  allow-newer: true 
tests/Critical.hs view
@@ -7,8 +7,6 @@  import           Algebra.Lattice import           Datafix-import           Datafix.Worklist       (Density (..), IterationBound (..),-                                         solveProblem) import           Datafix.Worklist.Graph (GraphRef) import           Numeric.Natural import           Test.Tasty@@ -20,11 +18,10 @@ instance BoundedJoinSemiLattice Natural where   bottom = 0 - fixLoop, fixDoubleDependency   :: GraphRef graph => (Node -> Density graph) -> Int -> Natural-fixLoop density n = solveProblem loopProblem (density (Node 0)) NeverAbort (Node n)-fixDoubleDependency density n = solveProblem doubleDependencyProblem (density (Node 1)) NeverAbort (Node n)+fixLoop density n = solveProblem loopFramework (density (Node 0)) NeverAbort (dependOn @(DependencyM _ Natural) (Node n))+fixDoubleDependency density n = solveProblem doubleDependencyFramework (density (Node 1)) NeverAbort (dependOn @(DependencyM _ Natural) (Node n))  tests :: [TestTree] tests =@@ -44,17 +41,17 @@           [ testCase "stabilizes at 4" (fixDoubleDependency Dense 0 @?= 4)           ]       , testGroup "Abortion"-          [ testCase "stabilizes at or over 4" (assertBool ">= 4" $ solveProblem doubleDependencyProblem Sparse (AbortAfter 1 (+ 4)) (Node 0) >= 4)+          [ testCase "stabilizes at or over 4" (assertBool ">= 4" $ solveProblem doubleDependencyFramework Sparse (AbortAfter 1 (+ 4)) (dependOn @(DependencyM _ Natural) (Node 0)) >= 4)           ]       ]   ] -mkDFP :: forall m . (Domain m ~ Natural) => (Node -> LiftedFunc Natural m) -> DataFlowProblem m-mkDFP transfer = DFP transfer (const (eqChangeDetector @(Domain m)))+mkDFF :: forall m . (Domain m ~ Natural) => (Node -> LiftedFunc Natural m) -> DataFlowFramework m+mkDFF transfer = DFF transfer (const (eqChangeDetector @(Domain m)))  -- | One node graph with loop that stabilizes after 10 iterations.-loopProblem :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowProblem m-loopProblem = mkDFP transfer+loopFramework :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowFramework m+loopFramework = mkDFF transfer   where     transfer (Node 0) = do -- stabilizes at 10       n <- dependOn @m (Node 0)@@ -68,8 +65,8 @@ -- unstable, so that it gets iterated again, which results in a value of -- 4 instead of e.g. 3 (= 1 + 2, the values of @B@ in the first iteration -- of @A@).-doubleDependencyProblem :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowProblem m-doubleDependencyProblem = mkDFP transfer+doubleDependencyFramework :: forall m . (MonadDependency m, Domain m ~ Natural) => DataFlowFramework m+doubleDependencyFramework = mkDFF transfer   where     transfer (Node 0) = do -- stabilizes at 4       n <- dependOn @m (Node 1)
+ tests/FirstFollow.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE FlexibleContexts #-}++module FirstFollow where++import           Prelude hiding (seq, exp)++import           SetRecurrences.FirstFollow+import qualified Data.Set as Set+import           Test.Tasty+import           Test.Tasty.HUnit++tests :: [TestTree]+tests =+  [ testGroup "Dyck"+      [ testFirst 3 dyck "S(S)" ["(((", "(()", "()", "()("]+      , testFollow 3 dyck 'S' ["###",")##",")((",")()","))#","))(",")))"]+      ]+  , testGroup "LL(1), not SLL(k)"+      [ testFirst 3 llsll "A" ["","a"]+      , testFollow 3 llsll 'A' ["ab#","b##"]+      ]+  , testGroup "empty"+      [ testFirst 3 emptyL "A" []+      , testFollow 3 emptyL 'A' ["###"]+      ]+  , testGroup "Left recursion"+      [ testFirst 3 leftrec "A" ["c","cab"]+      , testFollow 3 leftrec 'A' ["a##","aba"]+      ]+  ] where+      testFirst :: Int -> Grammar Char Char -> String -> [String] -> TestTree+      testFirst k gr seq exp =+        testCase ("First_" ++ show k ++ "('" ++ seq ++ "')") $+          first k gr (map (mkV gr) seq) @?= Set.fromList exp+      testFollow :: Int -> Grammar Char Char -> Char -> [String] -> TestTree+      testFollow k gr nt exp =+        testCase ("Follow_" ++ show k ++ "(" ++ show nt ++ ")") $+          follow k gr nt @?= Set.fromList (map (map mkWithEOF) exp)+      mkV gr v+        | elem v (terminals gr)    = T v+        | elem v (nonterminals gr) = NT v+        | otherwise                = error "not part of vocabulary"+      mkWithEOF '#' = EOF+      mkWithEOF c   = NoEOF c
tests/Main.hs view
@@ -1,5 +1,6 @@ import qualified Critical import qualified StrAnal+import qualified FirstFollow import           System.Environment import           Test.Tasty import qualified Trivial@@ -16,5 +17,8 @@         ]     , testGroup "Analyses"         [ testGroup "Strictness" StrAnal.tests+        ]+    , testGroup "Set recurrences"+        [ testGroup "First/Follow" FirstFollow.tests         ]     ]
tests/Trivial.hs view
@@ -1,13 +1,12 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies        #-}+{-# LANGUAGE TypeApplications    #-} {-# OPTIONS_GHC -fno-warn-orphans #-}  module Trivial (tests) where  import           Algebra.Lattice import           Datafix-import           Datafix.Worklist       (Density (..), IterationBound (..),-                                         solveProblem) import           Datafix.Worklist.Graph (GraphRef) import           Numeric.Natural import           Test.Tasty@@ -25,9 +24,9 @@  fixFib, fixFac, fixMutualRecursive   :: GraphRef graph => (Node -> Density graph) -> Int -> Natural-fixFib density n = solveProblem fibProblem (density (Node n)) NeverAbort (Node n)-fixFac density n = solveProblem facProblem (density (Node n)) NeverAbort (Node n)-fixMutualRecursive density n = solveProblem mutualRecursiveProblem (density (Node 1)) NeverAbort (Node n)+fixFib density n = solveProblem fibFramework (density (Node n)) NeverAbort (dependOn @(DependencyM _ Natural) (Node n))+fixFac density n = solveProblem facFramework (density (Node n)) NeverAbort (dependOn @(DependencyM _ Natural) (Node n))+fixMutualRecursive density n = solveProblem mutualRecursiveFramework (density (Node 1)) NeverAbort (dependOn @(DependencyM _ Natural) (Node n))  tests :: [TestTree] tests =@@ -51,7 +50,7 @@           , testCase "second node is stable" (fixMutualRecursive Dense 1 @?= 10)           ]       , testGroup "Abortion"-          [ testCase "aborts after 5 updates with value 42" (solveProblem mutualRecursiveProblem Sparse (AbortAfter 5 (const 42)) (Node 1) @?= 42)+          [ testCase "aborts after 5 updates with value 42" (solveProblem mutualRecursiveFramework Sparse (AbortAfter 5 (const 42)) (dependOn @(DependencyM _ Natural) (Node 1)) @?= 42)           ]       ]   ]
tests/doctest.hs view
@@ -1,5 +1,9 @@-import System.FilePath.Glob+import Build_doctests import Test.DocTest+import System.Environment (unsetEnv)  main :: IO ()-main = glob "src/**/*.hs" >>= doctest+main = do+  unsetEnv "GHC_ENVIRONMENT"+  let args = flags ++ pkgs ++ module_sources+  doctest args