diff --git a/README.md b/README.md index c3b38bb..d5a2a7a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,106 @@ -# rock +# rock [![Hackage](https://img.shields.io/hackage/v/rock.svg)](https://hackage.haskell.org/package/rock) -A build system inspired by _Build systems à la carte_ and Haxl. +A build system inspired by [Build systems à la carte](https://www.microsoft.com/en-us/research/publication/build-systems-la-carte/) and [Haxl](http://hackage.haskell.org/package/haxl). + +Used in [Sixten](https://github.com/ollef/sixten) and +[Sixty](https://github.com/ollef/sixty) to achieve incremental and query driven +compiler architectures. + +# Example + +```haskell +{-# language GADTs #-} +{-# language NoImplicitPrelude #-} +{-# language OverloadedStrings #-} +{-# language StandaloneDeriving #-} +{-# language TemplateHaskell #-} + +import Protolude + +import Data.GADT.Compare.TH (deriveGEq, deriveGCompare) +import qualified Rock + +data Query a where + A :: Query Integer + B :: Query Integer + C :: Query Integer + D :: Query Integer + +deriving instance Show (Query a) + +deriveGEq ''Query +deriveGCompare ''Query + +rules :: Rock.Rules Query +rules key = do + putText $ "Fetching " <> show key + case key of + A -> pure 10 + B -> do + a <- Rock.fetch A + pure $ a + 20 + C -> do + a <- Rock.fetch A + pure $ a + 30 + D -> + (+) <$> Rock.fetch B <*> Rock.fetch C + +main :: IO () +main = do + do + putText "Running" + result <- Rock.runTask Rock.sequentially rules (Rock.fetch D) + print result + do + putText "Running with memoisation" + memoVar <- newMVar mempty + result <- + Rock.runTask + Rock.sequentially + (Rock.memoise memoVar rules) + (Rock.fetch D) + print result + do + putText "Running with memoisation using the parallel strategy" + memoVar <- newMVar mempty + result <- + Rock.runTask + Rock.inParallel + (Rock.memoise memoVar rules) + (Rock.fetch D) + print result +``` + +Prints + +``` +Running +Fetching D +Fetching B +Fetching A +Fetching C +Fetching A +70 +Running with memoisation +Fetching D +Fetching B +Fetching A +Fetching C +70 +Running with memoisation using the parallel strategy +Fetching D +Fetching C +Fetching B +Fetching A +70 +``` + +# Related projects + +* [Shake](http://hackage.haskell.org/package/shake) +* [Salsa](https://crates.io/crates/salsa) + +# Contributions + +... are very welcome, especially in the areas of documentation, examples, +testing, and benchmarking. diff --git a/examples/Spreadsheet.hs b/examples/Spreadsheet.hs new file mode 100644 index 0000000..653e4e6 --- /dev/null +++ b/examples/Spreadsheet.hs @@ -0,0 +1,60 @@ +{-# language GADTs #-} +{-# language NoImplicitPrelude #-} +{-# language OverloadedStrings #-} +{-# language StandaloneDeriving #-} +{-# language TemplateHaskell #-} + +import Protolude + +import Data.GADT.Compare.TH (deriveGEq, deriveGCompare) +import qualified Rock + +data Query a where + A :: Query Integer + B :: Query Integer + C :: Query Integer + D :: Query Integer + +deriving instance Show (Query a) + +deriveGEq ''Query +deriveGCompare ''Query + +rules :: Rock.Rules Query +rules key = do + putText $ "Fetching " <> show key + case key of + A -> pure 10 + B -> do + a <- Rock.fetch A + pure $ a + 20 + C -> do + a <- Rock.fetch A + pure $ a + 30 + D -> + (+) <$> Rock.fetch B <*> Rock.fetch C + +main :: IO () +main = do + do + putText "Running" + result <- Rock.runTask Rock.sequentially rules (Rock.fetch D) + print result + do + putText "Running with memoisation" + memoVar <- newMVar mempty + result <- + Rock.runTask + Rock.sequentially + (Rock.memoise memoVar rules) + (Rock.fetch D) + print result + do + putText "Running with memoisation using the parallel strategy" + memoVar <- newMVar mempty + result <- + Rock.runTask + Rock.inParallel + (Rock.memoise memoVar rules) + (Rock.fetch D) + print result diff --git a/rock.cabal b/rock.cabal index 23a2d53..60d4809 100644 --- a/rock.cabal +++ b/rock.cabal @@ -30,7 +30,6 @@ library exposed-modules: Rock Rock.Core - Rock.Examples Rock.HashTag Rock.Hashed Rock.Traces @@ -47,3 +46,18 @@ library source-repository head type: git location: https://github.com/ollef/rock + +flag examples + Description: "Build examples" + Default: False + Manual: True + +executable rock-spreadsheet + if !flag(examples) + buildable: False + main-is: Spreadsheet.hs + ghc-options: -Wall + -threaded + hs-source-dirs: examples + default-language: Haskell2010 + build-depends: base, rock, protolude, dependent-sum-template diff --git a/src/Rock/Examples.hs b/src/Rock/Examples.hs deleted file mode 100644 index 9102b0d..0000000 --- a/src/Rock/Examples.hs +++ /dev/null @@ -1,145 +0,0 @@ -{-# language DeriveGeneric #-} -{-# language FlexibleInstances #-} -{-# language GADTs #-} -{-# language MultiParamTypeClasses #-} -{-# language RankNTypes #-} -{-# language StandaloneDeriving #-} -module Rock.Examples where - -import Protolude - -import Data.Dependent.Sum -import Data.Functor.Classes -import Data.GADT.Compare -import Data.GADT.Show -import Text.Show - -import Rock - -------------------------------------------------------------------------------- -data ModuleName = ModuleName - deriving (Eq, Ord, Show, Generic) -instance Hashable ModuleName -data ModuleHeader = ModuleHeader ModuleName - deriving (Eq, Ord, Show, Generic) -instance Hashable ModuleHeader -data ParsedModule = ParsedModule ModuleHeader - deriving (Eq, Ord, Show, Generic) -instance Hashable ParsedModule - -data TaskKey a where - ParseModuleHeader :: ModuleName -> TaskKey (ModuleHeader, Text) - ParseModule :: ModuleName -> TaskKey ParsedModule - -instance GEq TaskKey where - geq a b = case gcompare a b of - GLT -> Nothing - GEQ -> Just Refl - GGT -> Nothing - -gcompareEq :: Ord x => x -> x -> GOrdering a a -gcompareEq x y = case compare x y of - EQ -> GEQ - LT -> GLT - GT -> GGT - -instance GCompare TaskKey where - gcompare (ParseModuleHeader x) (ParseModuleHeader y) = gcompareEq x y - gcompare (ParseModule x) (ParseModule y) = gcompareEq x y - gcompare ParseModuleHeader {} _ = GLT - gcompare _ ParseModuleHeader {} = GGT - -deriving instance Show (TaskKey a) - -instance HashTag TaskKey where - hashTagged ParseModuleHeader {} = hash - hashTagged ParseModule {} = hash - -type CompilerTask = Task TaskKey -type CompilerRules = Rules TaskKey - -compilerRules :: CompilerRules -compilerRules (ParseModuleHeader mname) = parseModuleHeader mname -compilerRules (ParseModule mname) = parseModule mname - -parseModuleHeader :: ModuleName -> CompilerTask (ModuleHeader, Text) -parseModuleHeader mname = pure (ModuleHeader mname, "") - -parseModule :: ModuleName -> CompilerTask ParsedModule -parseModule mname = do - (header, _t) <- fetch (ParseModuleHeader mname) - pure $ ParsedModule header - -------------------------------------------------------------------------------- -data SheetKey a where - A :: SheetKey Integer - B :: SheetKey Integer - C :: SheetKey Integer - D :: SheetKey Integer - -instance GEq SheetKey where - geq a b = case gcompare a b of - GLT -> Nothing - GEQ -> Just Refl - GGT -> Nothing - -instance GCompare SheetKey where - gcompare A A = GEQ - gcompare B B = GEQ - gcompare C C = GEQ - gcompare D D = GEQ - gcompare A _ = GLT - gcompare _ A = GGT - gcompare B _ = GLT - gcompare _ B = GGT - gcompare C _ = GLT - gcompare _ C = GGT - -deriving instance Show (SheetKey a) - -instance HashTag SheetKey where - hashTagged A = hash - hashTagged B = hash - hashTagged C = hash - hashTagged D = hash - -instance GShow SheetKey where - gshowsPrec = showsPrec - -instance Show1 g => ShowTag SheetKey g where - showTaggedPrec A = showsPrec1 - showTaggedPrec B = showsPrec1 - showTaggedPrec C = showsPrec1 - showTaggedPrec D = showsPrec1 - -type SheetTask = Task SheetKey -type SheetRules = Rules SheetKey - -sheetRules :: SheetRules -sheetRules key = do - liftIO $ putText $ "computing " <> Protolude.show key - case key of - A -> pure 10 - B -> do - a <- fetch A - pure $ a + 20 - C -> do - a <- fetch A - pure $ a + 30 - D -> do - b <- fetch B - c <- fetch C - pure $ b + c - -sheetRules2 :: SheetRules -sheetRules2 key = - -- liftIO $ putText $ "computing 2 " <> Protolude.show key - case key of - A -> pure 12 - B -> do - a <- fetch A - pure $ a + 10 - C -> do - a <- fetch A - pure $ a + 20 - D -> (+) <$> fetch B <*> ((+) <$> fetch C <*> fetch C)