Skip to content

Commit d6277bf

Browse files
committed
🎸
0 parents  commit d6277bf

File tree

10 files changed

+495
-0
lines changed

10 files changed

+495
-0
lines changed

‎.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.stack-work

‎LICENSE

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Copyright Olle Fredriksson (c) 2018
2+
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
* Redistributions of source code must retain the above copyright
9+
notice, this list of conditions and the following disclaimer.
10+
11+
* Redistributions in binary form must reproduce the above
12+
copyright notice, this list of conditions and the following
13+
disclaimer in the documentation and/or other materials provided
14+
with the distribution.
15+
16+
* Neither the name of Author name here nor the names of other
17+
contributors may be used to endorse or promote products derived
18+
from this software without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

‎README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# rock

‎Setup.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

‎rock.cabal

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: rock
2+
version: 0.1.0.0
3+
-- synopsis:
4+
-- description:
5+
homepage: https://github.com/ollef/rock#readme
6+
license: BSD3
7+
license-file: LICENSE
8+
author: Olle Fredriksson
9+
maintainer: [email protected]
10+
copyright: 2018 Olle Fredriksson
11+
category: Web
12+
build-type: Simple
13+
extra-source-files: README.md
14+
cabal-version: >=1.10
15+
16+
library
17+
ghc-options: -Wall
18+
-Wcompat
19+
-Widentities
20+
-Wincomplete-record-updates
21+
-Wincomplete-uni-patterns
22+
-Wmissing-home-modules
23+
-Wpartial-fields
24+
-Wredundant-constraints
25+
-Wtabs
26+
-funbox-strict-fields
27+
hs-source-dirs: src
28+
exposed-modules:
29+
Examples
30+
Hashed
31+
Task
32+
VerifyingTraces
33+
build-depends: base >= 4.7 && < 5
34+
, dependent-map
35+
, dependent-sum
36+
, hashable
37+
, protolude
38+
default-language: Haskell2010
39+
default-extensions: OverloadedStrings, NoImplicitPrelude
40+
41+
source-repository head
42+
type: git
43+
location: https://github.com/ollef/rock

‎src/Examples.hs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
{-# language DeriveGeneric #-}
2+
{-# language GADTs #-}
3+
{-# language MultiParamTypeClasses #-}
4+
{-# language RankNTypes #-}
5+
{-# language StandaloneDeriving #-}
6+
module Examples where
7+
8+
import Protolude
9+
10+
import Data.Dependent.Sum
11+
import Data.GADT.Compare
12+
import Data.GADT.Show
13+
import Text.Show
14+
15+
import Hashed
16+
import Task
17+
18+
-------------------------------------------------------------------------------
19+
data ModuleName = ModuleName
20+
deriving (Eq, Ord, Show, Generic)
21+
instance Hashable ModuleName
22+
data ModuleHeader = ModuleHeader ModuleName
23+
deriving (Eq, Ord, Show, Generic)
24+
instance Hashable ModuleHeader
25+
data ParsedModule = ParsedModule ModuleHeader
26+
deriving (Eq, Ord, Show, Generic)
27+
instance Hashable ParsedModule
28+
29+
data TaskKey a where
30+
ParseModuleHeader :: ModuleName -> TaskKey (ModuleHeader, Text)
31+
ParseModule :: ModuleName -> TaskKey ParsedModule
32+
33+
instance GEq TaskKey where
34+
geq a b = case gcompare a b of
35+
GLT -> Nothing
36+
GEQ -> Just Refl
37+
GGT -> Nothing
38+
39+
gcompareEq :: Ord x => x -> x -> GOrdering a a
40+
gcompareEq x y = case compare x y of
41+
EQ -> GEQ
42+
LT -> GLT
43+
GT -> GGT
44+
45+
instance GCompare TaskKey where
46+
gcompare (ParseModuleHeader x) (ParseModuleHeader y) = gcompareEq x y
47+
gcompare (ParseModule x) (ParseModule y) = gcompareEq x y
48+
gcompare ParseModuleHeader {} _ = GLT
49+
gcompare _ ParseModuleHeader {} = GGT
50+
51+
deriving instance Show (TaskKey a)
52+
53+
instance HashTag TaskKey Identity where
54+
hashTagged ParseModuleHeader {} = hash
55+
hashTagged ParseModule {} = hash
56+
57+
type CompilerTask = Task TaskKey Identity
58+
type CompilerTasks = Tasks TaskKey Identity
59+
60+
compilerTasks :: CompilerTasks
61+
compilerTasks (ParseModuleHeader mname) = Identity <$> parseModuleHeader mname
62+
compilerTasks (ParseModule mname) = Identity <$> parseModule mname
63+
64+
parseModuleHeader :: ModuleName -> CompilerTask (ModuleHeader, Text)
65+
parseModuleHeader mname = pure (ModuleHeader mname, "")
66+
67+
parseModule :: ModuleName -> CompilerTask ParsedModule
68+
parseModule mname = do
69+
Identity (header, _t) <- fetch (ParseModuleHeader mname)
70+
pure $ ParsedModule header
71+
72+
-------------------------------------------------------------------------------
73+
data SheetKey a where
74+
A :: SheetKey Integer
75+
B :: SheetKey Integer
76+
C :: SheetKey Integer
77+
D :: SheetKey Integer
78+
79+
instance GEq SheetKey where
80+
geq a b = case gcompare a b of
81+
GLT -> Nothing
82+
GEQ -> Just Refl
83+
GGT -> Nothing
84+
85+
instance GCompare SheetKey where
86+
gcompare A A = GEQ
87+
gcompare B B = GEQ
88+
gcompare C C = GEQ
89+
gcompare D D = GEQ
90+
gcompare A _ = GLT
91+
gcompare _ A = GGT
92+
gcompare B _ = GLT
93+
gcompare _ B = GGT
94+
gcompare C _ = GLT
95+
gcompare _ C = GGT
96+
97+
deriving instance Show (SheetKey a)
98+
99+
instance HashTag SheetKey Identity where
100+
hashTagged A = hash
101+
hashTagged B = hash
102+
hashTagged C = hash
103+
hashTagged D = hash
104+
105+
instance GShow SheetKey where
106+
gshowsPrec = showsPrec
107+
108+
instance ShowTag SheetKey Identity where
109+
showTaggedPrec A = showsPrec
110+
showTaggedPrec B = showsPrec
111+
showTaggedPrec C = showsPrec
112+
showTaggedPrec D = showsPrec
113+
114+
type SheetTask = Task SheetKey Identity
115+
type SheetTasks = Tasks SheetKey Identity
116+
117+
sheetTasks :: SheetTasks
118+
sheetTasks key = do
119+
liftIO $ putText $ "computing " <> Protolude.show key
120+
case key of
121+
A -> pure $ Identity 10
122+
B -> do
123+
Identity a <- fetch A
124+
pure $ Identity $ a + 20
125+
C -> do
126+
Identity a <- fetch A
127+
pure $ Identity $ a + 30
128+
D -> do
129+
Identity b <- fetch B
130+
Identity c <- fetch C
131+
pure $ Identity $ b + c
132+
133+
sheetTasks2 :: SheetTasks
134+
sheetTasks2 key = do
135+
liftIO $ putText $ "computing 2 " <> Protolude.show key
136+
case key of
137+
A -> pure $ Identity 12
138+
B -> do
139+
Identity a <- fetch A
140+
pure $ Identity $ a + 10
141+
C -> do
142+
Identity a <- fetch A
143+
pure $ Identity $ a + 20
144+
D -> do
145+
Identity b <- fetch B
146+
Identity c <- fetch C
147+
pure $ Identity $ b + c

‎src/Hashed.hs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{-# language FlexibleContexts #-}
2+
{-# language FlexibleInstances #-}
3+
{-# language MultiParamTypeClasses #-}
4+
module Hashed(Hashed, hashed, unhashed, HashTag(hashTagged)) where
5+
6+
import Protolude
7+
8+
import Text.Show
9+
10+
import Data.Dependent.Sum
11+
12+
class HashTag k v where
13+
hashTagged :: k i -> v i -> Int
14+
15+
data Hashed v i = Hashed !(v i) !Int
16+
deriving (Show)
17+
18+
instance Eq (v i) => Eq (Hashed v i) where
19+
Hashed v1 h1 == Hashed v2 h2 = h1 == h2 && v1 == v2
20+
21+
instance Ord (v i) => Ord (Hashed v i) where
22+
compare (Hashed v1 _) (Hashed v2 _) = compare v1 v2
23+
24+
instance Hashable (Hashed v i) where
25+
hashWithSalt s (Hashed _ h) = hashWithSalt s h
26+
27+
instance ShowTag k v => ShowTag k (Hashed v) where
28+
showTaggedPrec k d (Hashed v _) = showParen (d > 10)
29+
$ showString "Hashed " . showTaggedPrec k 11 v
30+
31+
unhashed :: Hashed v i -> v i
32+
unhashed (Hashed x _) = x
33+
34+
hashed :: HashTag k v => k i -> v i -> Hashed v i
35+
hashed k v = Hashed v $ hashTagged k v

‎src/Task.hs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
{-# language DeriveFunctor #-}
2+
{-# language RankNTypes #-}
3+
{-# language ScopedTypeVariables #-}
4+
module Task where
5+
6+
import Protolude
7+
8+
import Data.Dependent.Map(DMap, GCompare)
9+
import qualified Data.Dependent.Map as DMap
10+
import Data.Functor.Compose
11+
12+
import Hashed
13+
import VerifyingTraces(VT)
14+
import qualified VerifyingTraces as VT
15+
16+
data Env k v = Env
17+
{ tasks :: !(Tasks k v)
18+
, tasksStartedVar :: !(MVar (DMap k (Compose MVar v)))
19+
, taskTracesVar :: !(MVar (VT k v))
20+
}
21+
22+
newtype Task k v a = Task { unTask :: Env k v -> IO a }
23+
deriving (Functor)
24+
25+
type Tasks k v = forall i. k i -> Task k v (v i)
26+
27+
runTask :: GCompare k => Tasks k v -> VT k v -> Task k v a -> IO (a, VT k v)
28+
runTask ts traces task = do
29+
tracesVar <- newMVar traces
30+
startedVar <- newMVar mempty
31+
a <- unTask task Env
32+
{ tasks = ts
33+
, tasksStartedVar = startedVar
34+
, taskTracesVar = tracesVar
35+
}
36+
traces' <- readMVar tracesVar
37+
return (a, traces')
38+
39+
build :: (GCompare k, HashTag k v) => Tasks k v -> VT k v -> k i -> IO (v i, VT k v)
40+
build ts traces key = runTask ts traces $ fetch key
41+
42+
instance Applicative (Task k v) where
43+
pure = Task . pure . pure
44+
Task f <*> Task x = Task $ (<*>) <$> f <*> x
45+
46+
instance Monad (Task k v) where
47+
Task ma >>= f = Task $ \env -> do
48+
a <- ma env
49+
unTask (f a) env
50+
51+
instance MonadIO (Task k v) where
52+
liftIO = Task . const
53+
54+
track :: forall k v a. GCompare k => Task k v a -> Task k v (a, DMap k v)
55+
track (Task task) = Task $ \env -> do
56+
depsVar <- newMVar mempty
57+
let
58+
tasks' :: forall i. k i -> Task k v (v i)
59+
tasks' k = Task $ \_env -> do
60+
v <- unTask (tasks env k) env
61+
modifyMVar_ depsVar $ pure . DMap.insert k v
62+
return v
63+
a <- task env { tasks = tasks' }
64+
deps <- readMVar depsVar
65+
return (a, deps)
66+
67+
fetchAsync :: (HashTag k v, GCompare k) => k i -> Task k v (Task k v (v i))
68+
fetchAsync key = Task $ \env -> do
69+
var <- newEmptyMVar
70+
_ <- forkIO $ do
71+
value <- unTask (fetch key) env
72+
putMVar var value
73+
return $ liftIO $ readMVar var
74+
75+
fetch :: (HashTag k v, GCompare k) => k i -> Task k v (v i)
76+
fetch key = Task $ \env -> do
77+
putText "fetching"
78+
let
79+
fromScratch = do
80+
putText "fromScratch"
81+
(value, deps) <- unTask (track $ tasks env key) env
82+
putText $ "deps " <> show (DMap.size deps)
83+
modifyMVar_ (taskTracesVar env)
84+
$ pure
85+
. VT.record key value deps
86+
return value
87+
88+
fetchHash k = hashed k <$> unTask (fetch k) env
89+
90+
checkDeps = do
91+
taskTraces <- readMVar $ taskTracesVar env
92+
case DMap.lookup key taskTraces of
93+
Nothing -> fromScratch
94+
Just oldValueDeps -> do
95+
upToDate <- VT.verifyDependencies (VT.dependencies oldValueDeps) fetchHash
96+
if upToDate then
97+
return $ unhashed $ VT.value oldValueDeps
98+
else
99+
fromScratch
100+
101+
join $ modifyMVar (tasksStartedVar env) $ \tasksStarted ->
102+
case DMap.lookup key tasksStarted of
103+
Nothing -> do
104+
valueVar <- newEmptyMVar
105+
let k = do
106+
value <- checkDeps
107+
putMVar valueVar value
108+
return value
109+
return (DMap.insert key (Compose valueVar) tasksStarted, k)
110+
Just (Compose valueVar) ->
111+
return (tasksStarted, readMVar valueVar)

0 commit comments

Comments
 (0)