Skip to content

Commit d027ada

Browse files
committed
initial code
1 parent e294d6f commit d027ada

35 files changed

+1273
-0
lines changed

Diff for: .github/workflows/test.hs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Data.Maybe
2+
import System.Environment
3+
import System.Process
4+
5+
main =
6+
do
7+
ghcString <- getEnv "ghc"
8+
let ghc = case ghcString of "8.10" -> GHC_8_10; "9.0" -> GHC_9_0
9+
callProcess "cabal" ("build" : "all" : constraints ghc)
10+
callProcess "cabal" ("test" : "all" : "--enable-tests" : constraints ghc)
11+
12+
x .= Just y = Just ("--constraint=" ++ x ++ "==" ++ y)
13+
x .= Nothing = Nothing
14+
15+
data GHC = GHC_8_10 | GHC_9_0
16+
17+
constraints ghc = catMaybes
18+
[ "base" .= case ghc of GHC_8_10 -> Just "4.14.*" ; GHC_9_0 -> Just "4.15.*"
19+
, "exceptions" .= case ghc of GHC_8_10 -> Just "0.10.4" ; GHC_9_0 -> Nothing
20+
, "hedgehog" .= case ghc of GHC_8_10 -> Just "1.0.4" ; GHC_9_0 -> Just "1.0.5"
21+
, "lifted-async" .= case ghc of GHC_8_10 -> Just "0.10.0.6" ; GHC_9_0 -> Just "0.10.2"
22+
, "monad-control" .= case ghc of GHC_8_10 -> Just "1.0.2.3" ; GHC_9_0 -> Nothing
23+
, "optics-core" .= case ghc of GHC_8_10 -> Just "0.3" ; GHC_9_0 -> Just "0.4"
24+
, "optics-th" .= case ghc of GHC_8_10 -> Just "0.3" ; GHC_9_0 -> Just "0.4"
25+
, "rank2classes" .= case ghc of GHC_8_10 -> Just "1.4.0.1" ; GHC_9_0 -> Just "1.4.2"
26+
, "transformers" .= case ghc of GHC_8_10 -> Just "0.5.6.2" ; GHC_9_0 -> Nothing
27+
, "transformers-base" .= case ghc of GHC_8_10 -> Just "0.4.5.1" ; GHC_9_0 -> Just "0.4.5.2"
28+
]

Diff for: .github/workflows/test.yml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
on: [push, pull_request]
2+
3+
name: Test the 'lazy-async' library
4+
5+
jobs:
6+
7+
build:
8+
name: Test the package
9+
runs-on: ubuntu-latest
10+
11+
strategy:
12+
matrix:
13+
ghc:
14+
- '8.10'
15+
- '9.0'
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
20+
- name: Cache Haskell dependencies
21+
uses: actions/cache@v2
22+
with:
23+
path: |
24+
~/.cabal/packages
25+
~/.cabal/store
26+
key: ${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.variant }}-${{ hashFiles('**/*.cabal', '.github/workflows/test.hs') }}
27+
restore-keys: |
28+
${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.variant }}-
29+
${{ runner.os }}-${{ matrix.ghc }}-
30+
${{ runner.os }}-
31+
32+
- uses: haskell/actions/setup@v1
33+
with:
34+
ghc-version: ${{ matrix.ghc }}
35+
36+
- name: Test
37+
run: runhaskell --ghc-arg='-package process' ./.github/workflows/test.hs
38+
env:
39+
ghc: ${{ matrix.ghc }}

Diff for: .stylish-haskell.yaml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# https://github.com/jaspervdj/stylish-haskell/blob/master/data/stylish-haskell.yaml
2+
3+
steps:
4+
5+
- simple_align:
6+
cases: true
7+
top_level_patterns: true
8+
9+
- imports:
10+
align: group
11+
list_align: after_alias
12+
long_list_align: inline
13+
list_padding: 4
14+
pad_module_names: true
15+
separate_lists: true
16+
17+
- trailing_whitespace: {}
18+
19+
columns: 80

Diff for: cabal.project

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
packages: lazy-async

Diff for: lazy-async/lazy-async.cabal

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
cabal-version: 3.0
2+
3+
name: lazy-async
4+
version: 1.0.0.0
5+
synopsis: Asynchronous actions that don't start right away
6+
7+
description:
8+
9+
Sometimes we have a bunch of 'IO' actions that do things like
10+
read files, make HTTP requests, or query a database. Some of the
11+
information that these actions produce might not end up being
12+
needed, depending on the breaks. In the interest of avoiding
13+
unnecessary effort, we don't want to simply run all the actions
14+
and collect their results upfront. We also don't want to simply
15+
run an action right before its result is needed, because it might
16+
be needed in more than one place, which opens the possibility of
17+
unnecessarily running the same action more than once. In
18+
situations like these, we use "LazyAsync".
19+
20+
Under the hood, an 'IO' action is turned into a @LazyAsync@ by
21+
constructing two things: An @Async@ (from the @async@ package),
22+
and a @TVar Bool@ (from the @stm@ package). The TVar, initialized
23+
to @False@, indicates whether the action is wanted yet. The async
24+
thread waits until the TVar turns @True@ and then runs the action.
25+
26+
homepage: https://github.com/typeclasses/lazy-async
27+
bug-reports: https://github.com/typeclasses/lazy-async/issues
28+
author: Chris Martin
29+
maintainer: Chris Martin, Julie Moronuki
30+
copyright: 2021 Mission Valley Software LLC
31+
license: MIT
32+
license-file: license.txt
33+
category: Concurrency
34+
build-type: Simple
35+
36+
source-repository head
37+
type: git
38+
location: https://github.com/typeclasses/lazy-async
39+
40+
common language
41+
default-language: Haskell2010
42+
ghc-options: -Wall
43+
default-extensions: DeriveFoldable
44+
default-extensions: DeriveFunctor
45+
default-extensions: DeriveTraversable
46+
default-extensions: ExistentialQuantification
47+
default-extensions: FlexibleContexts
48+
default-extensions: NoImplicitPrelude
49+
default-extensions: StandaloneDeriving
50+
51+
common dependencies
52+
build-depends: base ^>= 4.14 || ^>= 4.15
53+
build-depends: exceptions ^>= 0.10.4
54+
build-depends: lifted-async ^>= 0.10.0.6
55+
build-depends: monad-control ^>= 1.0.2.3
56+
build-depends: rank2classes ^>= 1.4.0.1
57+
build-depends: stm ^>= 2.5
58+
build-depends: transformers ^>= 0.5.6.2
59+
build-depends: transformers-base ^>= 0.4.5.1
60+
61+
common test-language
62+
import: language
63+
default-extensions: BlockArguments
64+
default-extensions: OverloadedStrings
65+
default-extensions: TemplateHaskell
66+
67+
common test-dependencies
68+
import: dependencies
69+
build-depends: hedgehog ^>= 1.0.4
70+
build-depends: lazy-async
71+
build-depends: optics-core ^>= 0.3 || ^>= 0.4
72+
build-depends: optics-th ^>= 0.3 || ^>= 0.4
73+
74+
common test-modules
75+
other-modules: Test.Counter
76+
other-modules: Test.Exceptions
77+
other-modules: Test.General
78+
other-modules: Test.Optics
79+
other-modules: Test.Person
80+
81+
common test
82+
import: test-language, test-dependencies, test-modules
83+
84+
library
85+
import: language, dependencies
86+
hs-source-dirs: src
87+
exposed-modules: LazyAsync
88+
other-modules: LazyAsync.Actions
89+
other-modules: LazyAsync.Actions.Empty
90+
other-modules: LazyAsync.Actions.Memoize
91+
other-modules: LazyAsync.Actions.Merge
92+
other-modules: LazyAsync.Actions.Poll
93+
other-modules: LazyAsync.Actions.Pure
94+
other-modules: LazyAsync.Actions.Spawn
95+
other-modules: LazyAsync.Actions.Start
96+
other-modules: LazyAsync.Actions.StartWait
97+
other-modules: LazyAsync.Actions.Wait
98+
other-modules: LazyAsync.Libraries.Async
99+
other-modules: LazyAsync.Libraries.Rank2
100+
other-modules: LazyAsync.Orphans
101+
other-modules: LazyAsync.Prelude
102+
other-modules: LazyAsync.Types
103+
other-modules: LazyAsync.Types.Complex
104+
other-modules: LazyAsync.Types.LazyAsync
105+
other-modules: LazyAsync.Types.NoAlternative
106+
other-modules: LazyAsync.Types.Outcome
107+
other-modules: LazyAsync.Types.Resource
108+
other-modules: LazyAsync.Types.StartPoll
109+
other-modules: LazyAsync.Types.Status
110+
111+
test-suite test
112+
import: test
113+
hs-source-dirs: test
114+
type: exitcode-stdio-1.0
115+
main-is: test.hs

Diff for: lazy-async/license.txt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Copyright 2021 Mission Valley Software LLC
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy of
4+
this software and associated documentation files (the "Software"), to deal in
5+
the Software without restriction, including without limitation the rights to
6+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7+
the Software, and to permit persons to whom the Software is furnished to do so,
8+
subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Diff for: lazy-async/src/LazyAsync.hs

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
{-# language Safe #-}
2+
3+
{- |
4+
5+
__What is this__ — A 'LazyAsync' is an action that doesn't start right away.
6+
When it does run, it runs in a separate thread.
7+
8+
__How to get one__ — The 'lazyAsync' function makes a 'LazyAsync' available
9+
within a 'ContT' context because it ensures the asynchronous action is cancelled
10+
when the continuation ends, to avoid accidentally leaving any unneeded threads
11+
running in the background.
12+
13+
__How to use it__ — You can incite a 'LazyAsync' to begin by using 🚀 'start',
14+
and then you can use ⏸️ 'wait' to block until it completes. There is also
15+
🚀⏸️ 'startWait', which does both.
16+
17+
If the only thing you ever do with your 'LazyAsync's is 'startWait' on them,
18+
then you may consider using 'memoize' instead, which does not require
19+
interacting with the 'LazyAsync' type at all.
20+
21+
-}
22+
23+
module LazyAsync
24+
( {- * LazyAsync -} LazyAsync,
25+
{- * Spawning -} lazyAsync,
26+
{- * Getting results -} startWait,
27+
{- * Combining actions -} apply, choose, merge,
28+
{- * Catching (Outcome) -} startWaitCatch, Outcome (..),
29+
applyOutcome, chooseOutcome,
30+
{- * Polling (Status) -} poll, Status (..),
31+
applyStatus, chooseStatus,
32+
{- * Starting manually -} start, wait, waitCatch,
33+
{- * Manual cancellation -} acquire, Resource (..),
34+
{- * Transactions -} pollSTM, startSTM, waitCatchSTM,
35+
{- * Memoization -} memoize,
36+
{- * Bulk operations -} {- $bulk -}
37+
manyLazyAsyncs, memoizeMany, memoizeRank2,
38+
{- * Notes on monads -} {- $monads -}
39+
{- * Unlifted variants -} {- $unlifted -}
40+
withLazyAsyncIO, startWaitIO, startWaitCatchIO,
41+
pollIO, startIO, waitIO, waitCatchIO,
42+
acquireIO, withLazyAsyncListIO,
43+
withMemoizedIO, withMemoizedListIO,
44+
{- * Re-exports -} {- $re-exports -}
45+
ContT (ContT, runContT), evalContT,
46+
MonadBaseControl (liftBaseWith, restoreM, StM),
47+
MonadBase (liftBase),
48+
MonadIO (liftIO)
49+
) where
50+
51+
import LazyAsync.Actions
52+
import LazyAsync.Orphans ()
53+
import LazyAsync.Prelude
54+
import LazyAsync.Types
55+
56+
{- $bulk
57+
58+
If you have a list (or other 'Traversable') of actions, the "many" functions
59+
('manyLazyAsyncs' and 'memoizeMany') can create a thread for each action in the
60+
list.
61+
62+
If you have a big recordful of actions and feel like getting real fancy, try
63+
making your datatype "higher-kinded" and using 'memoizeRank2' to automatically
64+
create a bunch of threads at once. You'll need the @rank2classes@ package; see
65+
"Rank2" and "Rank2.TH".
66+
67+
-}
68+
69+
{- $monads
70+
71+
__Working with ContT__ — Compose actions within the 'ContT' monadic context, and
72+
apply 'evalContT' at the top to run the continuation. You can also apply
73+
'runContT' to a 'ContT' action to convert it to a "continuation-passing style"
74+
higher-order function.
75+
76+
__Working with MonadBaseControl and StM__ — Most of the functions in this module
77+
are generalized using 'MonadBaseControl', which allows you to work in monads
78+
other than 'System.IO.IO' (to see an example of this, see the test suite for
79+
this package, which creates 'LazyAsync's in Hedgehog's @PropertyT@ context).
80+
'StM' is a type family which often "disappears" (that is, @'StM' m a ~ a@ for
81+
many @m@).
82+
83+
-}
84+
85+
{- $unlifted
86+
87+
If you are uninterested in monad transformers, you may prefer the
88+
functions in this section.
89+
90+
* All of the @m@ type variables are specialized to 'System.IO.IO',
91+
thus eliminating 'MonadBase', 'MonadBaseControl', 'MonadIO', and
92+
'StM' from the types
93+
94+
* Async spawning is done with explicit continuation passing instead of
95+
'ContT' actions
96+
97+
* 'Traversable'-constrained type constructors are specialized to @[]@
98+
99+
-}
100+
101+
{- $re-exports
102+
103+
Some key monad lifting concepts from other
104+
packages are re-exported from this module.
105+
106+
__base__ ("Control.Monad.IO.Class")
107+
108+
* 'MonadIO'
109+
* 'liftIO'
110+
111+
__transformers__ ("Control.Monad.Trans.Cont")
112+
113+
* 'ContT'
114+
* 'runContT'
115+
* 'evalContT'
116+
117+
__monad-base__ ("Control.Monad.Base")
118+
119+
* 'MonadBase'
120+
* 'liftBase'
121+
122+
__monad-control__ ("Control.Monad.Trans.Control")
123+
124+
* 'MonadBaseControl'
125+
* 'liftBaseWith'
126+
* 'restoreM'
127+
* 'StM'
128+
129+
-}

Diff for: lazy-async/src/LazyAsync/Actions.hs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{-# language Safe #-}
2+
3+
module LazyAsync.Actions (module X) where
4+
5+
import LazyAsync.Actions.Empty as X
6+
import LazyAsync.Actions.Memoize as X
7+
import LazyAsync.Actions.Merge as X
8+
import LazyAsync.Actions.Poll as X
9+
import LazyAsync.Actions.Pure as X
10+
import LazyAsync.Actions.Spawn as X
11+
import LazyAsync.Actions.Start as X
12+
import LazyAsync.Actions.StartWait as X
13+
import LazyAsync.Actions.Wait as X

Diff for: lazy-async/src/LazyAsync/Actions/Empty.hs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{-# language Safe #-}
2+
3+
module LazyAsync.Actions.Empty where
4+
5+
import LazyAsync.Types (LazyAsync (..), NoAlternative (..), Outcome (..),
6+
Status (..))
7+
8+
import LazyAsync.Prelude (toException)
9+
10+
emptyOutcome :: Outcome a
11+
emptyOutcome = Failure (toException NoAlternative)
12+
13+
emptyStatus :: Status a
14+
emptyStatus = Done emptyOutcome
15+
16+
emptyLazyAsync :: LazyAsync a
17+
emptyLazyAsync = Empty

0 commit comments

Comments
 (0)