Skip to content

Commit 481c086

Browse files
authored
Merge pull request #83 from tweag/api-and-documentation
Preparing for release: api and documentation
2 parents 1d7a594 + 7ec5c4b commit 481c086

File tree

12 files changed

+93
-49
lines changed

12 files changed

+93
-49
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Stack
2+
.stack-work
3+
4+
# Cabal
5+
dist/

capability.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ library
3939
Capability
4040
Capability.Accessors
4141
Capability.Constraints
42-
Capability.Context
42+
Capability.Derive
4343
Capability.Error
4444
Capability.Reader
4545
Capability.Reader.Internal.Class

src/Capability.hs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,29 @@
5151
-- Then you can use @foo@ at type @MyM@. Or any other type which can provide
5252
-- these capabilites.
5353
--
54+
-- === Functional capabilities
55+
--
56+
-- When writing applications, as opposed to libraries, a capability /name/ often
57+
-- determines its type parameters. It can be tiresome to write
58+
--
59+
-- @
60+
-- f :: HasReader "config" Config m => …
61+
-- @
62+
--
63+
-- over and over again.
64+
--
65+
-- To avoid this, each capability comes with a /functional/—here
66+
-- @HasReader\'@—variant (in this terminology @HasReader@ is
67+
-- /relational/). Where the type is deduced from the capability's name. The
68+
-- mapping from name to type is done with the @'Capability.TypeOf.TypeOf'@
69+
-- family, which is re-exported by every capability module.
70+
--
71+
-- @
72+
-- type instance TypeOf Symbol "config" = Config
73+
--
74+
-- f :: HasReader' "config" m => …
75+
-- @
76+
--
5477
-- == Module structure
5578
--
5679
-- Each module introduces a capability type class (or several related type
@@ -85,6 +108,15 @@
85108
-- combinators which you can use if you absolutely must: they are correct, but
86109
-- inefficient, so we recommend that you do not.
87110
--
111+
-- Finally there is
112+
--
113+
-- * "Capability.Derive"
114+
--
115+
-- Which exports a (still experimental) 'Capability.Derive.derive' function,
116+
-- which lets you run a computation which requires capabilities which are not
117+
-- directly provided by the ambient monad, but can be derived from the
118+
-- capabilities provided by the ambient monad.
119+
--
88120
-- == Further considerations
89121
--
90122
-- The tags of capabilities can be of any kind, they are not restricted to

src/Capability/Context.hs renamed to src/Capability/Derive.hs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,39 @@
99
{-# LANGUAGE TypeApplications #-}
1010
{-# LANGUAGE TypeOperators #-}
1111

12-
module Capability.Context where
12+
module Capability.Derive where
1313

1414
import Capability.Constraints
1515
import Data.Coerce (Coercible)
1616
import Unsafe.Coerce (unsafeCoerce)
1717

18-
-- | Execute the given action with an additional @inner@ capability derived from
19-
-- current context via the @t@ wrapper, retaining the list @cs@ of capabilities.
20-
context ::
18+
-- | Runs an action that requires additional capabilities.
19+
--
20+
-- @'derive' \@t \@derived \@ambient act@ runs @act@ by providing both the
21+
-- capabilities in @derived@ and @ambient@. The difference is that @ambient@
22+
-- capabilities are assumed to be available, whereas @derived@ instances are
23+
-- provided by @t@.
24+
--
25+
-- 'derive' assumes that @t@ is a newtype defined in the form:
26+
--
27+
-- @
28+
-- newtype T m a = T (m a)
29+
-- @
30+
--
31+
-- Then 'derive' uses type-class instances for `T` to provide for each of the
32+
-- capabilities in @derived@.
33+
--
34+
-- A common instance of this is 'Capability.Error.wrapError', whereby exceptions
35+
-- raised by @act@ can be repackaged in a larger exception type.
36+
--
37+
-- The @derive@ function is experimental and is subject to change.
38+
derive ::
2139
forall t (derived :: [Capability]) (ambient :: [Capability]) m a.
2240
( forall x. Coercible (t m x) (m x)
2341
, All derived (t m)
2442
, All ambient m)
2543
=> (forall m'. (All derived m', All ambient m') => m' a) -> m a
26-
context action =
44+
derive action =
2745
let tmDict = Dict @(All derived (t m))
2846
mDict =
2947
-- Note: this use of 'unsafeCoerce' should be safe thanks the Coercible
@@ -33,4 +51,4 @@ context action =
3351
unsafeCoerce @_ @(Dict (All derived m)) tmDict in
3452
case mDict of
3553
Dict -> action
36-
{-# INLINE context #-}
54+
{-# INLINE derive #-}

src/Capability/Error.hs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,17 @@
4646
{-# OPTIONS_GHC -Wno-simplifiable-class-constraints #-}
4747

4848
module Capability.Error
49-
( -- * Interface
49+
( -- * Relational capabilities
5050
HasThrow(..)
51-
, HasThrow'
5251
, throw
5352
, HasCatch(..)
54-
, HasCatch'
5553
, catch
5654
, catchJust
5755
, wrapError
56+
-- * Functional capabilities
57+
, HasThrow'
58+
, HasCatch'
59+
, TypeOf
5860
-- * Strategies
5961
, MonadError(..)
6062
, MonadThrow(..)
@@ -70,7 +72,7 @@ module Capability.Error
7072

7173
import Capability.Accessors
7274
import Capability.Constraints
73-
import Capability.Context (context)
75+
import Capability.Derive (derive)
7476
import Capability.TypeOf
7577
import Control.Exception (Exception(..))
7678
import qualified Control.Exception.Safe as Safe
@@ -168,14 +170,7 @@ wrapError :: forall innertag t (cs :: [Capability]) inner m a.
168170
, All cs m)
169171
=> (forall m'. All (HasCatch innertag inner ': cs) m' => m' a) -> m a
170172
wrapError =
171-
context @t @'[HasCatch innertag inner] @cs
172-
-- wrapError :: forall outertag innertag t outer inner m a.
173-
-- ( forall x. Coercible (t m x) (m x)
174-
-- , forall m'. HasCatch outertag outer m'
175-
-- => HasCatch innertag inner (t m')
176-
-- , HasCatch outertag outer m )
177-
-- => (forall m'. HasCatch innertag inner m' => m' a) -> m a
178-
-- wrapError action = coerce @(t m a) action
173+
derive @t @'[HasCatch innertag inner] @cs
179174
{-# INLINE wrapError #-}
180175

181176
-- XXX: Does it make sense to add a HasMask capability similar to @MonadMask@?

src/Capability/Reader.hs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,18 @@
99
-- a change is local, and does not persist when the 'local' call ends.
1010

1111
module Capability.Reader
12-
( -- * Interface
12+
( -- * Relational capability
1313
module Capability.Reader.Internal.Class
14+
-- * Functional capability
15+
, HasReader'
16+
, TypeOf
1417
-- * Strategies
1518
, module Capability.Reader.Internal.Strategies
1619
-- ** Modifiers
1720
, module Capability.Accessors
18-
-- * Helpers
19-
, module Capability.Constraints
20-
, module Capability.TypeOf
21-
, HasReader'
2221
) where
2322

2423
import Capability.Accessors
25-
import Capability.Constraints
2624
import Capability.Reader.Internal.Class
2725
import Capability.Reader.Internal.Strategies
2826
import Capability.TypeOf

src/Capability/Reader/Internal/Class.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module Capability.Reader.Internal.Class
2323

2424
import Capability.Constraints
2525
import Capability.Source.Internal.Class
26-
import Capability.Context (context)
26+
import Capability.Derive (derive)
2727
import Data.Coerce (Coercible)
2828
import GHC.Exts (Proxy#, proxy#)
2929

@@ -101,5 +101,5 @@ magnify :: forall innertag t (cs :: [Capability]) inner m a.
101101
, All cs m)
102102
=> (forall m'. All (HasReader innertag inner ': cs) m' => m' a) -> m a
103103
magnify =
104-
context @t @'[HasReader innertag inner] @cs
104+
derive @t @'[HasReader innertag inner] @cs
105105
{-# INLINE magnify #-}

src/Capability/Sink.hs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,20 @@
2222
{-# LANGUAGE PolyKinds #-}
2323

2424
module Capability.Sink
25-
( -- * Interface
25+
( -- * Relational capability
2626
module Capability.Sink.Internal.Class
27+
-- * Functional capability
28+
, HasSink'
29+
, TypeOf
2730
-- * Strategies
2831
, module Capability.Sink.Internal.Strategies
2932
-- ** Modifiers
3033
, module Capability.Accessors
31-
-- * Helpers
32-
, module Capability.Constraints
33-
, module Capability.TypeOf
34-
, HasSink'
3534
) where
3635

3736
import Capability.Sink.Internal.Class
3837
import Capability.Sink.Internal.Strategies
3938
import Capability.Accessors
40-
import Capability.Constraints
4139
import Capability.TypeOf
4240

4341
-- | Type synonym using the 'TypeOf' type family to specify 'HasSink'

src/Capability/Source.hs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,18 @@
3232
{-# LANGUAGE UndecidableInstances #-}
3333

3434
module Capability.Source
35-
( -- * Interface
35+
( -- * Relational capability
3636
module Capability.Source.Internal.Class
37+
-- * Functional capability
38+
, HasSource'
39+
, TypeOf
3740
-- * Strategies
3841
, module Capability.Source.Internal.Strategies
3942
-- ** Modifiers
4043
, module Capability.Accessors
41-
-- * Helpers
42-
, module Capability.Constraints
43-
, module Capability.TypeOf
44-
, HasSource'
4544
) where
4645

4746
import Capability.Accessors
48-
import Capability.Constraints
4947
import Capability.Source.Internal.Class
5048
import Capability.Source.Internal.Strategies
5149
import Capability.TypeOf

src/Capability/State.hs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,18 @@
1313
-- or "Capability.Stream".
1414

1515
module Capability.State
16-
( -- * Interface
16+
( -- * Relational capability
1717
module Capability.State.Internal.Class
18+
-- * Functional capability
19+
, HasState'
20+
, TypeOf
1821
-- * Strategies
1922
, module Capability.State.Internal.Strategies
2023
-- ** Modifiers
2124
, module Capability.Accessors
22-
-- * Helpers
23-
, module Capability.Constraints
24-
, module Capability.TypeOf
25-
, HasState'
2625
) where
2726

2827
import Capability.Accessors
29-
import Capability.Constraints
3028
import Capability.State.Internal.Class
3129
import Capability.State.Internal.Strategies
3230
import Capability.TypeOf

src/Capability/State/Internal/Class.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module Capability.State.Internal.Class
2525
) where
2626

2727
import Capability.Constraints
28-
import Capability.Context (context)
28+
import Capability.Derive (derive)
2929
import Capability.Source.Internal.Class
3030
import Capability.Sink.Internal.Class
3131
import Data.Coerce (Coercible)
@@ -127,5 +127,5 @@ zoom :: forall innertag t (cs :: [Capability]) inner m a.
127127
, All cs m )
128128
=> (forall m'. All (HasState innertag inner ': cs) m' => m' a) -> m a
129129
zoom =
130-
context @t @'[HasState innertag inner] @cs
130+
derive @t @'[HasState innertag inner] @cs
131131
{-# INLINE zoom #-}

src/Capability/Writer.hs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@
4040
{-# OPTIONS_GHC -Wno-simplifiable-class-constraints -Wno-deprecations #-}
4141

4242
module Capability.Writer
43-
( -- * Interface
43+
( -- * Relational capability
4444
HasWriter(..)
45-
, HasWriter'
4645
, writer
4746
, tell
4847
, listen
4948
, pass
49+
-- * Functional capability
50+
, HasWriter'
51+
, TypeOf
5052
-- * Strategies
5153
, WriterLog
5254
, StreamLog

0 commit comments

Comments
 (0)