Skip to content

Commit 091e3b1

Browse files
authored
Merge pull request #26 from aspiwack/strat-redesign
Completely redesign the API around explicit strategies
2 parents 8f21d7b + d7d7886 commit 091e3b1

File tree

8 files changed

+196
-180
lines changed

8 files changed

+196
-180
lines changed

README.md

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,27 +24,26 @@ The Benign library is an attempt to address this gap. A difficulty is
2424
laziness. With laziness, things have a beginning (when the thunk is
2525
being forced), but not a well-defined end. So what do we measure the
2626
time of? The solution of the Benign library is to be less lazy. We
27-
keep laziness for algorithms, but use strict (or at least stricter)
28-
types to assemble bigger steps. It's fine to log or trace in pure
29-
code, since we don't consider that these observations are part of the
30-
semantics of the program.
27+
keep laziness for algorithms, but use evaluate more strictly when
28+
assembling bigger steps. It's fine to log or trace in pure code, since
29+
we don't consider that these observations are part of the semantics of
30+
the program.
3131

3232
The Benign library provides facilities to create benign effects,
33-
including to use strict types to assemble these large steps.
33+
including evaluation strategies to express precisely how strict we
34+
want to be.
3435

3536
The premise underlying all this, as well as the implementation of the
3637
library, is that logging or tracing is not very fast. So we don't want
3738
to log or trace in places where performance is really essential. This
3839
is why at the most inner level, where tight loops and algorithms live,
3940
laziness is not a problem: we are not going to log there, this would
40-
cost too much performance. At a more outer level, we can use
41-
strictness to make steps with a beginning and an end. It's ok if there
42-
is a cost in terms of conversion, this is not where we need to
43-
optimise too much. The library can, and does, prevent optimisation
44-
through its functions (note that cost-centre profiling also prevents
45-
optimisation through cost centres; it isn't surprising that we are
46-
having a similar problem). With the optimisation not working at that
47-
level, strictness is much less of a problem.
41+
cost too much performance. The library can, and does, prevent
42+
optimisation through its functions anyway (note that cost-centre
43+
profiling also prevents optimisation through cost centres; it isn't
44+
surprising that we are having a similar problem). So benign effects
45+
all must happen at rather macro steps, where we don't have to worry
46+
too much about the impact of evaluation.
4847

4948
## Backends
5049

backends/katip/src/Benign/Katip.hs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,34 @@ katipNamespace = unsafePerformIO Benign.newField
2121
{-# NOINLINE katipNamespace #-}
2222

2323
-- | See 'Katip.katipAddContext'.
24-
withKatipContext :: (Katip.LogItem i, Benign.Eval a) => i -> a -> Benign.Result a
24+
withKatipContext :: (Katip.LogItem i) => i -> Benign.Strat a -> a -> a
2525
withKatipContext item = Benign.withAltering katipContext addContext
2626
where
2727
addContext (Just st) = Just $ st <> Katip.liftPayload item
2828
addContext Nothing = error "todo"
2929

3030
-- | See 'Katip.katipAddNamespace'.
31-
withKatipNamespace :: Benign.Eval a => Katip.Namespace -> a -> Benign.Result a
31+
withKatipNamespace :: Katip.Namespace -> Benign.Strat a -> a -> a
3232
withKatipNamespace namespace = Benign.withAltering katipNamespace addNamespace
3333
where
3434
addNamespace (Just st) = Just $ st <> namespace
3535
addNamespace Nothing = error "todo"
3636

3737
-- | Within this computation, Katip is configured.
3838
withKatip ::
39-
(Katip.LogItem c, Benign.EvalIO a) =>
39+
(Katip.LogItem c) =>
4040
Katip.LogEnv ->
4141
c ->
4242
Katip.Namespace ->
43-
a ->
44-
IO (Benign.ResultIO a)
45-
withKatip env ctx namespace =
46-
Benign.withSettingIO katipEnv env
47-
. Benign.withSettingIO katipContext (Katip.liftPayload ctx)
48-
. Benign.withSettingIO katipNamespace namespace
43+
Benign.Strat a ->
44+
IO a ->
45+
IO a
46+
withKatip env ctx namespace strat =
47+
Benign.withSettingIO' katipEnv env
48+
. Benign.withSettingIO' katipContext (Katip.liftPayload ctx)
49+
. Benign.withSettingIO katipNamespace namespace strat
4950

50-
logLocM :: forall a. (Benign.Eval a, HasCallStack) => Katip.Severity -> Katip.LogStr -> a -> Benign.Result a
51+
logLocM :: forall a. (HasCallStack) => Katip.Severity -> Katip.LogStr -> Benign.Strat a -> a -> a
5152
logLocM severity str = withFrozenCallStack spanLog
5253
where
5354
-- The whole purpose of naming `span` is to freeze the call stack. It's
@@ -58,7 +59,7 @@ logLocM severity str = withFrozenCallStack spanLog
5859
-- scratch. This would be invisible. I tried to harden this function by
5960
-- declaring type signatures everywhere. I haven't tested it yet though. It
6061
-- may be wrong.
61-
spanLog :: HasCallStack => a -> Benign.Result a
62+
spanLog :: HasCallStack => Benign.Strat a -> a -> a
6263
spanLog = Benign.unsafeSpanBenign doLog (return ())
6364

6465
doLog :: HasCallStack => IO ()

backends/timestats/src/Benign/TimeStats.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
module Benign.TimeStats where
44

55
import Benign qualified
6+
import Control.Exception
67
import Debug.TimeStats qualified as TimeStats
78
import System.IO.Unsafe (unsafePerformIO)
89

9-
measure :: Benign.Eval a => String -> a -> Benign.Result a
10-
measure label thing = unsafePerformIO $ TimeStats.measureM label $ Benign.evalIO (Benign.PureEval thing)
10+
measure :: String -> Benign.Strat a -> a -> a
11+
measure label strat thing = unsafePerformIO $ TimeStats.measureM label $ do Benign.E <- evaluate (strat thing); return thing
1112
{-# NOINLINE measure #-}

benign.cabal

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ library
3434
, containers
3535
, deepseq
3636
, stm
37-
, strict-wrapper
3837
, transformers
3938
default-language: Haskell2010
4039

@@ -50,6 +49,5 @@ executable simple-print
5049
, containers
5150
, deepseq
5251
, stm
53-
, strict-wrapper
5452
, transformers
5553
default-language: Haskell2010

examples/SimplePrint.hs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
module Main where
44

5-
import Benign (Seq (..))
65
import Benign qualified
76
import Data.Maybe
87
import GHC.IO.Unsafe (unsafePerformIO)
@@ -30,15 +29,15 @@ context = unsafePerformIO Benign.newField
3029
{-# NOINLINE context #-}
3130

3231
-- 'withContext' is called to extend the context in its scope.
33-
withContext :: Benign.Eval a => String -> a -> Benign.Result a
32+
withContext :: String -> Benign.Strat a -> a -> a
3433
withContext additional_ctx = Benign.withAltering context $ \ctx ->
3534
Just $
3635
fromMaybe "" ctx ++ " " ++ additional_ctx
3736

3837
-- The 'log' function is the one performing the logging. It is a little
3938
-- degenerate, as far as benign effects go, as it doesn't do anything after the
4039
-- end of the evaluation.
41-
log :: Benign.Eval a => String -> a -> Benign.Result a
40+
log :: String -> Benign.Strat a -> a -> a
4241
log log_line = Benign.unsafeSpanBenign do_log (return ())
4342
where
4443
do_log :: IO ()
@@ -53,10 +52,10 @@ log log_line = Benign.unsafeSpanBenign do_log (return ())
5352
------------------------------------------------------------------------------
5453

5554
(+:) :: Int -> Int -> Int
56-
n +: p = (withContext "left:" (Seq n)) + (withContext "right:" (Seq p))
55+
n +: p = (withContext "left:" Benign.whnf n) + (withContext "right:" Benign.whnf p)
5756

5857
incr :: Int -> Int
59-
incr n = log (show n) $ Seq $ n + 1
58+
incr n = log (show n) Benign.whnf $ n + 1
6059

6160
myvalue :: Int
6261
myvalue = incr 18 +: incr 42 +: incr 57

package.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ dependencies:
1313
- containers
1414
- deepseq
1515
- stm
16-
- strict-wrapper
1716
- transformers
1817

1918
ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wnoncanonical-monad-instances -Wredundant-constraints

0 commit comments

Comments
 (0)