on develop help sign in
Merge branch 'develop' into patchmapwithmove2
f72c230John Ericson
ChangeLog.md+28−7
@@ -2,11 +2,19 @@
2
2
3## Unreleased
3## Unreleased
4
4
5+* Add `Reflex.Query.Base.mapQueryT`. See that module for documentation
6+
7+## 0.6.3
8+
5−* Data.WeakBag.traverse and Data.FastWeakBag.traverse have been
9+* `Data.WeakBag.traverse` and `Data.FastWeakBag.traverse` have been deprecated.
6− renamed to Data.WeakBag.traverse_ and Data.FastWeakBag.traverse_
10+ They are replaced with `Data.WeakBag.traverse_` and `Data.FastWeakBag.traverse_`, respectively.
7− respectively.
11+
8* Fixes a bug in `Reflex.Patch.MapWithMove.patchThatSortsMapWith` that was producing invalid `PatchMapWithMove`.
12* Fixes a bug in `Reflex.Patch.MapWithMove.patchThatSortsMapWith` that was producing invalid `PatchMapWithMove`.
9
13
14+* Add missing `NotReady` instances:
15+ - `instance NotReady (SpiderTimeline x) (SpiderHost x)`
16+ - `instance HasSpiderTimeline x => NotReady (SpiderTimeline x) (PerformEventT (SpiderTimeline x) (SpiderHost x))`
17+
10## 0.6.2.4
18## 0.6.2.4
11
19
12* Update to monoidal-containers 0.6
20* Update to monoidal-containers 0.6
@@ -18,7 +26,9 @@
18## 0.6.2.2
26## 0.6.2.2
19
27
20* Support these >= 1. Add `split-these` flag to control whether to use new these/semialign combination or not.
28* Support these >= 1. Add `split-these` flag to control whether to use new these/semialign combination or not.
29+
21* Update version bounds to fix some CI failures
30* Update version bounds to fix some CI failures
31+
22* Add travis CI configuration
32* Add travis CI configuration
23
33
24## 0.6.2.1
34## 0.6.2.1
@@ -33,31 +43,42 @@
33 * Add incrementalCoercion/coerceIncremental to go with dynamicCoercion/coerceDynamic
43 * Add incrementalCoercion/coerceIncremental to go with dynamicCoercion/coerceDynamic
34
44
35* Generalize merging functions:
45* Generalize merging functions:
36− `merge` to `mergeG`,
46+ `merge` to `mergeG`,
37− `mergeIncremental` to `mergeIncrementalG`,
47+ `mergeIncremental` to `mergeIncrementalG`,
38− `mergeIncrementalWithMove` to `mergeIncrementalWithMoveG`.
48+ `mergeIncrementalWithMove` to `mergeIncrementalWithMoveG`.
39
49
40* Generalize distribute function:
50* Generalize distribute function:
41 `distributeDMapOverDynPure` to `distributeDMapOverDynPureG`,
51 `distributeDMapOverDynPure` to `distributeDMapOverDynPureG`,
42
52
43## 0.6.2.0
53## 0.6.2.0
44
54
45−* Add `Reflex.Query.Base.mapQueryT`. See that module for documentation
55+* Fix `holdDyn` so that it is lazy in its event argument
56+ These produce `DMap`s whose values needn't be `Identity`.
57+
46* Stop using the now-deprecated `*Tag` classes (e.g., `ShowTag`).
58* Stop using the now-deprecated `*Tag` classes (e.g., `ShowTag`).
59+
47* Fix `holdDyn` so that it is lazy in its event argument.
60* Fix `holdDyn` so that it is lazy in its event argument.
48
61
49## 0.6.1.0
62## 0.6.1.0
50
63
51* Re-export all of `Data.Map.Monoidal`
64* Re-export all of `Data.Map.Monoidal`
65+
52* Fix `QueryT` and `RequesterT` tests
66* Fix `QueryT` and `RequesterT` tests
53
67
54## 0.6.0.0 -- 2019-03-20
68## 0.6.0.0 -- 2019-03-20
55
69
56* Deprecate `FunctorMaybe` in favor of `Data.Witherable.Filterable`. We still export `fmapMaybe`, `ffilter`, etc., but they all rely on `Filterable` now.
70* Deprecate `FunctorMaybe` in favor of `Data.Witherable.Filterable`. We still export `fmapMaybe`, `ffilter`, etc., but they all rely on `Filterable` now.
71+
57* Rename `MonadDynamicWriter` to `DynamicWriter` and add a deprecation for the old name.
72* Rename `MonadDynamicWriter` to `DynamicWriter` and add a deprecation for the old name.
73+
58* Remove many deprecated functions.
74* Remove many deprecated functions.
75+
59* Add a `Num` instance for `Dynamic`.
76* Add a `Num` instance for `Dynamic`.
77+
60* Add `matchRequestsWithResponses` to make it easier to use `Requester` with protocols that don't do this matching for you.
78* Add `matchRequestsWithResponses` to make it easier to use `Requester` with protocols that don't do this matching for you.
79+
61* Add `withRequesterT` to map functions over the request and response of a `RequesterT`.
80* Add `withRequesterT` to map functions over the request and response of a `RequesterT`.
81+
62* Suppress nil patches in `QueryT` as an optimization. The `Query` type must now have an `Eq` instance.
82* Suppress nil patches in `QueryT` as an optimization. The `Query` type must now have an `Eq` instance.
83+
63* Add `throttleBatchWithLag` to `Reflex.Time`. See that module for details.
84* Add `throttleBatchWithLag` to `Reflex.Time`. See that module for details.
Quickref.md+14−11
@@ -198,7 +198,7 @@ For Events, the returned Event fires whenever the latest Event supplied by the w
198The functions mentioned above are used to create a static FRP network.
198The functions mentioned above are used to create a static FRP network.
199There are additional typeclasses that can be used to modify the FRP network, to have it interact with IO action, or to introspect the building of the network.
199There are additional typeclasses that can be used to modify the FRP network, to have it interact with IO action, or to introspect the building of the network.
200
200
201−Th typeclasses and their associated annotations include:
201+The typeclasses and their associated annotations include:
202
202
203- `PostBuild`
203- `PostBuild`
204 Fire an Event when an FRP network has been set up.
204 Fire an Event when an FRP network has been set up.
@@ -206,7 +206,7 @@ Th typeclasses and their associated annotations include:
206 [B] -- Function runs in any monad supporting PostBuild
206 [B] -- Function runs in any monad supporting PostBuild
207 ```
207 ```
208
208
209−- `Adjustable`
209+- `Adjustable`
210 Use Events to add or remove pieces of an FRP network.
210 Use Events to add or remove pieces of an FRP network.
211 ```haskell
211 ```haskell
212 [A] -- Function runs in any monad supporting Adjustable
212 [A] -- Function runs in any monad supporting Adjustable
@@ -271,7 +271,7 @@ Th typeclasses and their associated annotations include:
271```haskell
271```haskell
272-- Run side-effecting actions in Event when it occurs; returned Event contains
272-- Run side-effecting actions in Event when it occurs; returned Event contains
273-- results. Side effects run in the (Performable m) monad which is associated with
273-- results. Side effects run in the (Performable m) monad which is associated with
274−-- the (PerformEvent t m) typeclass constraint.
274+-- the (PerformEvent t m) typeclass constraint.
275-- This allows for working with IO when a ((MonadIO (Performable m)) constraint is available.
275-- This allows for working with IO when a ((MonadIO (Performable m)) constraint is available.
276[P] performEvent :: Event (Performable m a ) -> m (Event a)
276[P] performEvent :: Event (Performable m a ) -> m (Event a)
277
277
@@ -295,17 +295,20 @@ Th typeclasses and their associated annotations include:
295## Networks
295## Networks
296
296
297```haskell
297```haskell
298−-- Functions from Reflex.Network used to deal with Dynamics/Events carrying (m a)
298+-- Functions from Reflex.Adjustable / Reflex.Network used to deal with Dynamics/Events carrying (m a)
299
299
300+[A] runWithReplace :: m a -> Event t (m b) -> m (a, Event t b)
301+
300−-- Given a Dynamic of network-creating actions, create a network that is recreated whenever the Dynamic updates.
302+-- Given a Dynamic of network-creating actions, create a network that is recreated whenever the Dynamic updates.
301−-- The returned Event of network results occurs when the Dynamic does. Note: Often, the type a is an Event,
303+-- The returned Event of network results occurs when the Dynamic does. Note: Often, the type a is an Event,
302-- in which case the return value is an Event-of-Events that would typically be flattened (via switchHold).
304-- in which case the return value is an Event-of-Events that would typically be flattened (via switchHold).
303−[P,A] networkView :: Dynamic (m a) -> m (Event a)
305+[P,A] networkView :: Dynamic (m a) -> m (Event a)
304
306
305−-- Given an initial network and an Event of network-creating actions, create a network that is recreated whenever the
307+-- Given an initial network and an Event of network-creating actions, create a network that is recreated whenever the
306−-- Event fires. The returned Dynamic of network results occurs when the Event does. Note: Often, the type a is an
308+-- Event fires. The returned Dynamic of network results occurs when the Event does. Note: Often, the type a is an
307-- Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
309-- Event, in which case the return value is a Dynamic-of-Events that would typically be flattened.
308−[H,A] networkHold :: m a -> Event (m a) -> m (Dynamic a)
310+[H,A] networkHold :: m a -> Event (m a) -> m (Dynamic a)
309
311
310-- Render a placeholder network to be shown while another network is not yet done building
312-- Render a placeholder network to be shown while another network is not yet done building
311−[P,A] untilReady :: m a -> m b -> m (a, Event b)
313+[P,A] untilReady :: m a -> m b -> m (a, Event b)
314+```
dep/reflex-platform/github.json+3−3
@@ -1,7 +1,7 @@
1{
1{
2 "owner": "reflex-frp",
2 "owner": "reflex-frp",
3 "repo": "reflex-platform",
3 "repo": "reflex-platform",
4− "branch": "jailbreakTheselens",
4+ "branch": "develop",
5− "rev": "4284ed527c96c373538dc7e31776d9a50ca6aa91",
5+ "rev": "e7b76dd552a10916c7d8702c11292dac4f4299ea",
6− "sha256": "1m1nkxq7ng9wnqbd77xn8d81f2iz8g61y5m0r3gp0gi0q59jm8ay"
6+ "sha256": "0s1183arrwldcs50qhzgnv94v24n9bgq6dfq64wp0a3q2nzyvgwh"
7}
7}
reflex.cabal+2−3
@@ -1,5 +1,5 @@
1Name: reflex
1Name: reflex
2−Version: 0.6.2.4
2+Version: 0.6.3
3Synopsis: Higher-order Functional Reactive Programming
3Synopsis: Higher-order Functional Reactive Programming
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
4Description: Reflex is a high-performance, deterministic, higher-order Functional Reactive Programming system
5License: BSD3
5License: BSD3
@@ -58,13 +58,12 @@ library
58 data-default >= 0.5 && < 0.8,
58 data-default >= 0.5 && < 0.8,
59 dependent-map >= 0.3 && < 0.4,
59 dependent-map >= 0.3 && < 0.4,
60 exception-transformers == 0.4.*,
60 exception-transformers == 0.4.*,
61− profunctors >= 5.3 && < 5.5,
62 lens >= 4.7 && < 5,
61 lens >= 4.7 && < 5,
63 monad-control >= 1.0.1 && < 1.1,
62 monad-control >= 1.0.1 && < 1.1,
64 mtl >= 2.1 && < 2.3,
63 mtl >= 2.1 && < 2.3,
65 prim-uniq >= 0.1.0.1 && < 0.2,
64 prim-uniq >= 0.1.0.1 && < 0.2,
66 primitive >= 0.5 && < 0.8,
65 primitive >= 0.5 && < 0.8,
67− profunctors,
66+ profunctors >= 5.3 && < 5.5,
68 random == 1.1.*,
67 random == 1.1.*,
69 ref-tf == 0.4.*,
68 ref-tf == 0.4.*,
70 reflection == 2.1.*,
69 reflection == 2.1.*,
release.nix+27−17
@@ -17,26 +17,36 @@ let
17 ] ++ lib.optionals (reflex-platform.iosSupport) [
17 ] ++ lib.optionals (reflex-platform.iosSupport) [
18 "ghcIosAarch64"
18 "ghcIosAarch64"
19 ];
19 ];
20+ variations = map (v: "reflex" + v) [
21+ "-dontUseTemplateHaskell"
22+ ""
23+ ];
20− hsPkgs = lib.genAttrs compilers (ghc: let
24+ compilerPkgs = lib.genAttrs compilers (ghc: let
21− ghc' = reflex-platform.${ghc}.override {
25+ variationPkgs = lib.genAttrs variations (variation: let
22− overrides = self: super: let
26+ reflex-platform = reflex-platform-fun {
27+ inherit system;
28+ __useTemplateHaskell = variation == "reflex"; # TODO hack
29+ haskellOverlays = [
30+ # Use this package's source for reflex
31+ (self: super: {
32+ _dep = super._dep // {
23− reflexSrc = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [
33+ reflex = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [
24− "default.nix"
25− "release.nix"
34+ "release.nix"
26− ".git"
35+ ".git"
27− "dist"
36+ "dist"
28− ])) ./.;
37+ ])) ./.;
29− in {
38+ };
30− reflex-dontUseTemplateHaskell = self.callCabal2nixWithOptions "reflex" reflexSrc "-f -use-template-haskell" {};
39+ })
31− reflex = self.callCabal2nixWithOptions "reflex" reflexSrc "-f +use-template-haskell" {};
40+ ];
32 };
41 };
33− };
42+ in reflex-platform.${ghc}.reflex);
34− in {
43+ in variationPkgs // {
35− inherit (ghc') reflex reflex-dontUseTemplateHaskell;
44+ cache = reflex-platform.pinBuildInputs "reflex-${system}-${ghc}"
45+ (builtins.attrValues variationPkgs);
36 });
46 });
37− in hsPkgs // {
47+ in compilerPkgs // {
38 cache = reflex-platform.pinBuildInputs "reflex-${system}"
48 cache = reflex-platform.pinBuildInputs "reflex-${system}"
39− (lib.concatLists (map builtins.attrValues (builtins.attrValues hsPkgs)));
49+ (map (a: a.cache) (builtins.attrValues compilerPkgs));
40 });
50 });
41
51
42 metaCache = native-reflex-platform.pinBuildInputs "reflex-everywhere"
52 metaCache = native-reflex-platform.pinBuildInputs "reflex-everywhere"
src/Control/Monad/ReaderIO.hs+1−1
@@ -37,7 +37,7 @@ instance Applicative (ReaderIO e) where
37#if MIN_VERSION_base(4,10,0)
37#if MIN_VERSION_base(4,10,0)
38 liftA2 = liftM2
38 liftA2 = liftM2
39 {-# INLINE liftA2 #-}
39 {-# INLINE liftA2 #-}
40−#endif
40+#endif
41 (*>) = (>>)
41 (*>) = (>>)
42 {-# INLINE (*>) #-}
42 {-# INLINE (*>) #-}
43
43
src/Data/AppendMap.hs+1−1
@@ -20,7 +20,7 @@ module Data.AppendMap
20 , module Data.Map.Monoidal
20 , module Data.Map.Monoidal
21 ) where
21 ) where
22
22
23−import Prelude hiding (map, null)
23+import Prelude hiding (null)
24
24
25import Data.Coerce
25import Data.Coerce
26import Data.Default
26import Data.Default
src/Reflex/Class.hs+2−1
@@ -286,7 +286,8 @@ class ( MonadHold t (PushM t)
286 -- | Create an 'Event' that will occur whenever the currently-selected input
286 -- | Create an 'Event' that will occur whenever the currently-selected input
287 -- 'Event' occurs
287 -- 'Event' occurs
288 switch :: Behavior t (Event t a) -> Event t a
288 switch :: Behavior t (Event t a) -> Event t a
289− -- | Create an 'Event' that will occur whenever the input event is occurring -- and its occurrence value, another 'Event', is also occurring
289+ -- | Create an 'Event' that will occur whenever the input event is occurring -- and its occurrence value, another 'Event', is also occurring.
290+ -- You maybe looking for '@switchHold@ @never@' instead.
290 coincidence :: Event t (Event t a) -> Event t a
291 coincidence :: Event t (Event t a) -> Event t a
291 -- | Extract the 'Behavior' of a 'Dynamic'.
292 -- | Extract the 'Behavior' of a 'Dynamic'.
292 current :: Dynamic t a -> Behavior t a
293 current :: Dynamic t a -> Behavior t a
src/Reflex/Collection.hs+1−1
@@ -130,7 +130,7 @@ listWithKeyShallowDiff initialVals valsChanged mkChild = do
130 Nothing -> Just Nothing
130 Nothing -> Just Nothing
131
131
132 -- We don't want to let spurious re-creations of items through
132 -- We don't want to let spurious re-creations of items through
133− Just _ -> Nothing
133+ Just _ -> Nothing
134 listHoldWithKey
134 listHoldWithKey
135 initialVals
135 initialVals
136 (attachWith (flip (Map.differenceWith relevantPatch))
136 (attachWith (flip (Map.differenceWith relevantPatch))
src/Reflex/DynamicWriter/Class.hs−1
@@ -26,4 +26,3 @@ class (Monad m, Monoid w) => DynamicWriter t w m | m -> t w where
26
26
27instance DynamicWriter t w m => DynamicWriter t w (ReaderT r m) where
27instance DynamicWriter t w m => DynamicWriter t w (ReaderT r m) where
28 tellDyn = lift . tellDyn
28 tellDyn = lift . tellDyn
29−
src/Reflex/Network.hs+1−1
@@ -20,7 +20,7 @@ import Reflex.NotReady.Class
20import Reflex.PostBuild.Class
20import Reflex.PostBuild.Class
21
21
22-- | A 'Dynamic' "network": Takes a 'Dynamic' of network-creating actions and replaces the network whenever the 'Dynamic' updates.
22-- | A 'Dynamic' "network": Takes a 'Dynamic' of network-creating actions and replaces the network whenever the 'Dynamic' updates.
23−-- The returned Event of network results fires when the 'Dynamic' updates.
23+-- The returned Event of network results fires at post-build time and when the 'Dynamic' updates.
24-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events, where the outer 'Event' fires
24-- Note: Often, the type 'a' is an Event, in which case the return value is an Event-of-Events, where the outer 'Event' fires
25-- when switching networks. Such an 'Event' would typically be flattened (via 'switchPromptly').
25-- when switching networks. Such an 'Event' would typically be flattened (via 'switchPromptly').
26networkView :: (NotReady t m, Adjustable t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
26networkView :: (NotReady t m, Adjustable t m, PostBuild t m) => Dynamic t (m a) -> m (Event t a)
src/Reflex/PerformEvent/Base.hs+1−1
@@ -141,7 +141,7 @@ hostPerformEventT a = do
141 case mToPerform of
141 case mToPerform of
142 Nothing -> return [result']
142 Nothing -> return [result']
143 Just toPerform -> do
143 Just toPerform -> do
144− responses <- runHostFrame $ traverseRequesterData (Identity <$>) toPerform
144+ responses <- runHostFrame $ traverseRequesterData (fmap Identity) toPerform
145 mrt <- readRef responseTrigger
145 mrt <- readRef responseTrigger
146 let followupEventTriggers = case mrt of
146 let followupEventTriggers = case mrt of
147 Just rt -> [rt :=> Identity responses]
147 Just rt -> [rt :=> Identity responses]
src/Reflex/Spider/Internal.hs+9
@@ -103,6 +103,7 @@ import qualified Reflex.Host.Class
103import Reflex.NotReady.Class
103import Reflex.NotReady.Class
104import Reflex.Patch
104import Reflex.Patch
105import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
105import qualified Reflex.Patch.DMapWithMove as PatchDMapWithMove
106+import Reflex.PerformEvent.Base (PerformEventT)
106
107
107#ifdef DEBUG_TRACE_EVENTS
108#ifdef DEBUG_TRACE_EVENTS
108import qualified Data.ByteString.Char8 as BS8
109import qualified Data.ByteString.Char8 as BS8
@@ -2705,3 +2706,11 @@ instance MonadAtomicRef (SpiderHostFrame x) where
2705instance PrimMonad (SpiderHostFrame x) where
2706instance PrimMonad (SpiderHostFrame x) where
2706 type PrimState (SpiderHostFrame x) = PrimState IO
2707 type PrimState (SpiderHostFrame x) = PrimState IO
2707 primitive = SpiderHostFrame . EventM . primitive
2708 primitive = SpiderHostFrame . EventM . primitive
2709+
2710+instance NotReady (SpiderTimeline x) (SpiderHost x) where
2711+ notReadyUntil _ = return ()
2712+ notReady = return ()
2713+
2714+instance HasSpiderTimeline x => NotReady (SpiderTimeline x) (PerformEventT (SpiderTimeline x) (SpiderHost x)) where
2715+ notReadyUntil _ = return ()
2716+ notReady = return ()
src/Reflex/Workflow.hs+1−1
@@ -34,7 +34,7 @@ workflow w0 = do
34 rec eResult <- networkHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
34 rec eResult <- networkHold (unWorkflow w0) $ fmap unWorkflow $ switch $ snd <$> current eResult
35 return $ fmap fst eResult
35 return $ fmap fst eResult
36
36
37−-- | Similar to 'workflow', but outputs an 'Event' that fires whenever the current 'Workflow' is replaced by the next 'Workflow'.
37+-- | Similar to 'workflow', but outputs an 'Event' that fires at post-build time and whenever the current 'Workflow' is replaced by the next 'Workflow'.
38workflowView :: forall t m a. (Reflex t, NotReady t m, Adjustable t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
38workflowView :: forall t m a. (Reflex t, NotReady t m, Adjustable t m, MonadFix m, MonadHold t m, PostBuild t m) => Workflow t m a -> m (Event t a)
39workflowView w0 = do
39workflowView w0 = do
40 rec eResult <- networkView . fmap unWorkflow =<< holdDyn w0 eReplace
40 rec eResult <- networkView . fmap unWorkflow =<< holdDyn w0 eReplace
test/Reflex/Bench/Focused.hs+1−1
@@ -134,7 +134,7 @@ holdDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynami
134holdDynChain = iterM (\d -> sample (current d) >>= flip holdDyn (updated d))
134holdDynChain = iterM (\d -> sample (current d) >>= flip holdDyn (updated d))
135
135
136buildDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
136buildDynChain :: (Reflex t, MonadHold t m) => Word -> Dynamic t Word -> m (Dynamic t Word)
137−buildDynChain = iterM (\d -> do
137+buildDynChain = iterM (\d -> do
138 let b = fmap (+1) (current d)
138 let b = fmap (+1) (current d)
139 e = fmap (*2) (updated d)
139 e = fmap (*2) (updated d)
140 buildDynamic (sample b) e)
140 buildDynamic (sample b) e)
test/hlint.hs−7
@@ -30,16 +30,9 @@ main = do
30 ]
30 ]
31 matchFile = and <$> sequence
31 matchFile = and <$> sequence
32 [ extension ==? ".hs"
32 [ extension ==? ".hs"
33− , let notElem' = liftOp notElem
34− in filePath `notElem'` filePathExceptions pwd
35 ]
33 ]
36 files <- find recurseInto matchFile (pwd </> "src") --TODO: Someday fix all hints in tests, etc.
34 files <- find recurseInto matchFile (pwd </> "src") --TODO: Someday fix all hints in tests, etc.
37 ideas <- fmap concat $ forM files $ \f -> do
35 ideas <- fmap concat $ forM files $ \f -> do
38 putStr $ "linting file " ++ drop (length pwd + 1) f ++ "... "
36 putStr $ "linting file " ++ drop (length pwd + 1) f ++ "... "
39 runHlint f
37 runHlint f
40 if null ideas then exitSuccess else exitFailure
38 if null ideas then exitSuccess else exitFailure
41−
42−filePathExceptions :: FilePath -> [FilePath]
43−filePathExceptions pwd = map (pwd </>) $
44− [ "src/Data/AppendMap.hs" -- parse error when hlint runs
45− ]