úÎé¡ÞŸ      !"#$%&'()*+,-./01234 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~  €  ‚ ƒ „ … † ‡ ˆ ‰ Š‹ŒŽ‘’“”•–—˜™š›œžSafe3 JAn abstract datatype for a key/value store with build information of type i.[Compute the hash of a given value. We typically assume cryptographic hashing, e.g. SHA256.A F is used for efficient tracking and sharing of build results. We use newtype Hash a = Hash a for prototyping.Read the build information.Read the value of a key.XRead the hash of a key's value. In some cases may be implemented more efficiently than hash . getValue k.Write the build information.Modify the build information. Update the value of a key. Initialise the store.    Ÿ ¡¢Safe+0QV£9An alternative type for task descriptions, isomorphic to  as demonstrated by functions € and ¥.hA task is used to compute the value of a key, by finding the necessary dependencies using the provided fetch :: k -> f v callback. associates a  with every non-input key. Nothing% indicates that the key is an input.ŠsCompose two task descriptions, preferring the first one in case there are two tasks corresponding to the same key.Safe+<QVh.NA model using Monad, works beautifully and allows storing the key on the disk.›The Applicative model requires every key to be able to associate with its environment (e.g. a reader somewhere). Does not support cutoff if a key changes.SafeQV"§GDefines a set partition. For a function to be a valid partition, if  f k == ks, then: k in ks forall i in ks . f i == ksŽGiven a build rule where you can build some combinations of multiple rules, use a partition to enable building lots of multiple rule subsets.SafeQV# -Find the dependencies of an applicative task.  Safe3QV&è!wA list of dependencies, and a function that when applied to those dependencies either the result or more dependencies.$dA list of dependencies, and a function that when applied to those dependencies produces the result.!#"$%&'&$%'!"#!"#$%SafeQV(*-)Find the dependency of a functorial task.--SafeQVh6Õ.'Execute a monadic task on a pure store k -> v, tracking the dependencies./9Execute a monadic task using an effectful fetch function k -> m v, tracking the dependencies.06Given a description of tasks, check if a key is input.1'Run a task with a pure lookup function.2,Convert a task with a total lookup function k -> m v- into a task with a partial lookup function k -> m (Maybe v);. This essentially lifts the task from the type of values v to Maybe v, where the result NothingA indicates that the task failed because of a missing dependency.3,Convert a task with a total lookup function k -> m v? into a task with a lookup function that can throw exceptions k -> m (Either e v);. This essentially lifts the task from the type of values v to  Either e v, where the result Left eL indicates that the task failed because of a failed dependency lookup, and Right v yeilds the value otherwise../0123./0123 Safe &'+FQTV;±4A typed build task.5‰A type class for keys, equipped with an associated type family that can be used to determine the type of value corresponding to the key.7EThe name of the key. Useful for avoiding heterogeneous lists of keys.8"Extract the names of dependencies.4567845678š©ª«¬­567 Safe+03;=QV>Õ<sGTask is a generalised Task wrapped in a newtype. It is generalised in the sense that it computes a value of type a given a fetch of type k -> f v.;<=>?<=>;?<=> SafeQVhE²N\An example of a non-deterministic task: generate a random number from a specified interval.OXRun a non-deterministic task with a pure lookup function, listing all possible results.PGiven a description of tasks , an initial store, and a result1 produced by running a build system on a target key, this function returns ® if the key='s value is a possible result of running the associated task.NOPNOP None345KNVgÙQ^A step trace, records the resulting value, the step it last build, the step where it changed.S/Invariant: if a DCT contains a trace for a key kŒ, then it must also contain traces for each of its non-input dependencies. Input keys cannot appear in a DCT because they are never built.¯zA tree of dependencies. It would be more efficient to use graphs, but trees are simpler and are sufficient for our model.TFAn abstract data type for a set of constructive traces equipped with ^, ], _ and a ° instance.UBAn abstract data type for a set of verifying traces equipped with [, \ and a ° instance.V.A trace is parameterised by the types of keys k , hashes h, as well as the result r. For verifying traces, r = h; for constructive traces,  Hash r = h.["Record a new trace for building a key with dependencies deps6, obtaining the hashes of up-to-date values by using  fetchHash.\BGiven a function to compute the hash of a key's current value, a key(, and a set of verifying traces, return ® if the key is up-to-date.]Check if a given key is dirty w.r.t a store.^"Record a new trace for building a key with dependencies deps6, obtaining the hashes of up-to-date values by using  fetchHash._BGiven a function to compute the hash of a key's current value, a key+, and a set of constructive traces, return  Just newValue‚ if it is possible to reconstruct it from the traces. Prefer reconstructing the currenct value, if it matches one of the traces.±6Extract the tree of input dependencies of a given key.²Like ±;, but replaces each key with the hash of its current value.`"Record a new trace for building a key with dependencies deps<, obtaining the hashes of up-to-date values from the given store.aBGiven a function to compute the hash of a key's current value, a key:, and a set of deterministic constructive traces, return  Just newValue5 if it is possible to reconstruct it from the traces.b"Record a new trace for building a key with dependencies deps.cBGiven a function to compute the hash of a key's current value, a key(, and a set of verifying traces, return ® if the key is up-to-date.QRSTUVWXZY[\]^_`abcVWXYZU[\T]^_S`aRQbcQ³RŽSµ¯¶·TžU¹VWXYZ None+NQVrø‚¹Given a key-value pair and the corresponding task, a rebuilder returns a new task that has access to the build information and can use it to skip rebuilding a key if it is up to date.ƒAlways rebuilds the key.„nThis rebuilder uses modification time to decide whether a key is dirty and needs to be rebuilt. Used by Make.…jThis rebuilders uses approximate dependencies to decide whether a key needs to be rebuilt. Used by Excel.†*This rebuilder relies on verifying traces.‡-This rebuilder relies on constructive traces.ˆ;This rebuilder relies on deterministic constructive traces.‰-This rebuilder relies on version/step traces.|}~€‚ƒ„…†‡ˆ‰‚ƒ„€…}~|†‰‡ˆ}~None†Ž º`Build a dependency graph given a function for computing dependencies of a key and a target key.»=Compute all keys reachable via dependecies from a target key.Œ2Compute the topological sort of a graph or return Nothing if the graph has cycles.œpGiven a function to compute successors of a vertex, apply it recursively starting from a given vertex. Returns Nothingå if this process does not terminate because of cycles. Note that the current implementation is very inefficient: it trades efficiency for simplicity. The resulting list is likely to contain an exponential number of duplicates.ŸxGiven a monadic function to compute successors of a vertex, apply it recursively starting from a given vertex. Returns Nothingå if this process does not terminate because of cycles. Note that the current implementation is very inefficient: it trades efficiency for simplicity. The resulting list is likely to contain an exponential number of duplicates.¿/Check that a predicate holds for all values of a.À7Check that a monadic predicate holds for all values of a.Á/Check that a predicate holds for some value of a.Â7Check that a monadic predicate holds for some value of a.ÃLogical implication. º»ŒœŸ¿ÀÁÂÃÃ0None+QVh”ªŠ&A build system takes a description of j, a target key, and a store, and computes a new store, where the key and its dependencies are up to date.‹Given a description of tasks , an initial store, and a result1 produced by running a build system on a target key, this function returns ® if the result. is a correct build outcome. Specifically: * result and storej must agree on the values of all inputs. In other words, no inputs were corrupted during the build. * result is  consistent with the tasksf, i.e. for every non-input key, the result of recomputing its task matches the value stored in the result.ŒGiven a build and tasks , check that buildC produces a correct result for any initial store and a target key.Check that a build system is  idempotentF, i.e. running it once or twice in a row leads to the same resulting .Š‹ŒŠŒ‹None <>?AKNQVhÂÇ Ä`Check if a key is dirty by examining its dependencies, as well as the stored build information.ŵAn item in the queue comprises a key that needs to be built and a list of keys that are blocked on it. More efficient implementations are possible, e.g. storing blocked keys in a  Map k [k]" would allow faster queue updates.ŽThe so-called calculation chain¡: the order in which keys were built during the previous build, which is used as the best guess for the current build by Excel and other similar build systems.ÆpUpdate the value of a key in the store. The function takes both the current value (the first parameter of type v3) and the new value (the second parameter of type vÎ), and can potentially avoid touching the store if the value is unchanged. The current implementation simply ignores the current value, but in future this may be optimised, e.g. by comparing their hashes.ÙThis scheduler constructs the dependency graph of the target key by extracting all (static) dependencies upfront, and then traversing the graph in the topological order, rebuilding keys using the supplied rebuilder.Ç,Convert a task with a total lookup function k -> m v? into a task with a lookup function that can throw exceptions k -> m (Either e v);. This essentially lifts the task from the type of values v to  Either e v, where the result Left eR indicates that the task failed, e.g. because of a failed dependency lookup, and Right v yeilds the value otherwise.ÿoA model of the scheduler used by Excel, which builds keys in the order used in the previous build. If a key cannot be build because its dependencies have changed and a new dependency is still dirty, the corresponding build task is abandoned and the key is moved at the end of the calculation chain, so it can be restarted when all its dependencies are up to date.ÈyAdd a key with a list of blocked keys to the queue. If the key is already in the queue, extend its list of blocked keys.ÉDExtract a key and a list of blocked keys from the queue, or return Nothing if the queue is empty.‘ÿ|A model of the scheduler used by Bazel. We extract a key K from the queue and try to build it. There are now two cases: 1. The build fails because one of the dependencies of K is dirty. In this case we add the dirty dependency to the queue, listing K as blocked by it. 2. The build succeeds, in which case we add all keys that were previously blocked by K to the queue.’ÿ This scheduler builds keys recursively: to build a key it first makes sure that all its dependencies are up to date and then executes the key's task. It stores the set of keys that have already been built as part of the state to avoid executing the same task twice.“²An incorrect scheduler that builds the target key without respecting its dependencies. It produces the correct result only if all dependencies of the target key are up to date.Ž‘’“Ž‘’“NoneVÞ/ ”{This is not a correct build system: given a target key, it simply rebuilds it, without rebuilding any of its dependencies.•ÝThis is a correct but non-minimal build system: given a target key it recursively rebuilds its dependencies, even if they are already up to date. There is no memoisation, therefore the a key may be built multiple times.–¬This is a correct but non-minimal build system: it will rebuild keys even if they are up to date. However, it performs memoization, therefore it never builds a key twice.—pA model of Make: an applicative build system that uses file modification times to check if a key is up to date.˜jA model of Ninja: an applicative build system that uses verifying traces to check if a key is up to date.™A model of Excel: a monadic build system that stores the calculation chain from the previuos build and approximate dependencies.šeA model of Shake: a monadic build system that uses verifying traces to check if a key is up to date.›ÿA model of Bazel: a monadic build system that uses constructive traces to check if a key is up to date as well as for caching build results. Note that Bazel currently does not allow users to write monadic build rules: only built-in rules have access to dynamic dependencies.œ“A model of Cloud Shake: a monadic build system that uses constructive traces to check if a key is up to date as well as for caching build results. A model of Buck: an applicative build system that uses deterministic constructive traces to check if a key is up to date as well as for caching build results.ž™A model of Nix: a monadic build system that uses deterministic constructive traces to check if a key is up to date as well as for caching build results. ”•–—˜™š›œž ”•–—˜›™šœžÊ !"#$%&'())*++,-./011233456789:;<=>?@A ' + ) B C D E F G G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~  €  ‚ ƒ „ … † ‡ ˆ ‰ Š ‹ Œ  Ž   ‘ ’“”•–—˜™š›œžŸ ¡¢£€¥Š§š©ª«¬­ ® ¯ ° ± ² ³Žµ¶ ·ž¹º » Œ [ \ ] œ Ÿ ^ _¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ"build-0.0.1-7cQjaHuKinxBvNhF0BUwzz Build.Store Build.TaskBuild.SelfTracking Build.MultiBuild.Task.ApplicativeBuild.Task.DependBuild.Task.FunctorBuild.Task.MonadBuild.Task.TypedBuild.Task.WrappedBuild.Task.MonadPlus Build.TraceBuild.RebuilderBuildBuild.Scheduler Build.SystemBuild.UtilitiesStoreHashablehashHashgetInfogetValuegetHashputInfomapInfoputValue initialise$fApplicativeHash $fFunctorHash $fHashable(,)$fHashableHash $fHashable[]$fHashableInteger $fHashableInt$fEqHash $fOrdHash $fShowHashTaskTasksValue ValueTaskKeyKeyTask selfTrackingM selfTrackingAmulti dependenciesDependsDoneDependtoDepend toDepends$fApplicativeDepend$fMonadDepends$fApplicativeDepends$fFunctorDepend$fFunctorDepends dependencytracktrackMisInputcomputepartial exceptionalshowKeyshowDependencies$fKeyExampleKey$fShowExampleKeyWrappedGTaskrunGTaskunwrap$fMonadPlusGTask$fAlternativeGTask$fAlternativeGTask0 $fMonadGTask $fMonadGTask0$fApplicativeGTask$fApplicativeGTask0$fApplicativeGTask1$fApplicativeGTask2$fFunctorGTask$fFunctorGTask0$fFunctorGTask1$fFunctorGTask2$fFunctorGTask3random computeNDcorrectBuildValueSTStepDCTCTVTTracekeydependsresultrecordVTverifyVT isDirtyCTrecordCT constructCT recordDCT constructDCTrecordSTverifyST$fHashableTree $fMonoidStep$fSemigroupStep $fShowTrace $fMonoidVT $fSemigroupVT $fMonoidCT $fSemigroupCT$fShowCT$fEqTree$fFoldableTree $fFunctorTree $fOrdTree $fShowTree$fTraversableTree $fMonoidDCT$fSemigroupDCT $fEnumStep$fEqStep $fOrdStep $fShowStep $fMonoidST $fSemigroupST$fShowSTApproximationInfoDependencyApproximationSubsetOfUnknownMakeInfoTime RebuilderperpetualRebuildermodTimeRebuilderapproximationRebuilder vtRebuilder ctRebuilder dctRebuilder stRebuilder correctBuildcorrect idempotentChain topological reordering restarting recursive independentdumbbusymemomakeninjaexcelshakebazel cloudShakebucknixinfovaluesTasks2 fromTaskstoTaskscompose Partition ExampleKeyBaseNumber SplitDigit LastDigit BaseDigitsghc-prim GHC.TypesTrueTreebaseGHC.BaseMonoid inputTree inputHashTreeLeafNodegraph reachabletopSortreachreachMforallforallMexistsexistsM==>IsDirtyQueue updateValuetryenqueuedequeue