Skip to content

Commit f4c6d3f

Browse files
Merge #925: Normal: reintroduce normalizeValueF
* Normal: reintroduce normalizeValueF * Normal: opaque: show ("expr" -> "cycle")
2 parents 875ca69 + ca71ed5 commit f4c6d3f

File tree

11 files changed

+149
-93
lines changed

11 files changed

+149
-93
lines changed

ChangeLog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
-- was :: v -> (m v -> m v) -> m v
5959
```
6060

61-
* [(link)](https://github.com/haskell-nix/hnix/pull/863/files) `Nix.Normal`: `normalizeValue` removed first functional argument that was passing the function that did the thunk forcing. Now function provides the thunk forcing. Now to normalize simply use `normalizeValue v`.
61+
* [(link)](https://github.com/haskell-nix/hnix/pull/863/files) `Nix.Normal`: `normalizeValue` removed first functional argument that was passing the function that did the thunk forcing. Now function provides the thunk forcing. Now to normalize simply use `normalizeValue v`. Old implementation now is `normalizeValueF`.
6262

6363
* [(link)](https://github.com/haskell-nix/hnix/pull/859/commits/8e043bcbda13ea4fd66d3eefd6da690bb3923edd) `Nix.Value.Equal`: `valueEqM`: freed from `RankNTypes: forall t f m .`.
6464

src/Nix.hs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -104,18 +104,21 @@ evaluateExpression
104104
-> (NValue t f m -> m a)
105105
-> NExprLoc
106106
-> m a
107-
evaluateExpression mpath evaluator handler expr = do
108-
opts :: Options <- asks (view hasLens)
109-
args <- traverse (traverse eval') $ fmap (second parseArg) (arg opts) <> fmap
110-
(second mkStr)
111-
(argstr opts)
112-
evaluator mpath expr >>= \f ->
113-
(\f' ->
114-
processResult handler =<<
115-
case f' of
116-
NVClosure _ g -> g (argmap args)
117-
_ -> pure f
118-
) =<< demand f
107+
evaluateExpression mpath evaluator handler expr =
108+
do
109+
opts :: Options <- asks $ view hasLens
110+
args <-
111+
(traverse . traverse)
112+
eval'
113+
$ (second parseArg <$> arg opts) <>
114+
(second mkStr <$> argstr opts)
115+
f <- evaluator mpath expr
116+
f' <- demand f
117+
val <-
118+
case f' of
119+
NVClosure _ g -> g $ argmap args
120+
_ -> pure f
121+
processResult handler val
119122
where
120123
parseArg s =
121124
either

src/Nix/Cited.hs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ instance ComonadEnv [Provenance m v] (NCited m v) where
5050
$(makeLenses ''Provenance)
5151
$(makeLenses ''NCited)
5252

53+
class HasCitations1 m v f where
54+
citations1 :: f a -> [Provenance m v]
55+
addProvenance1 :: Provenance m v -> f a -> f a
56+
5357
class HasCitations m v a where
5458
citations :: a -> [Provenance m v]
5559
addProvenance :: Provenance m v -> a -> a
@@ -58,18 +62,14 @@ instance HasCitations m v (NCited m v a) where
5862
citations = _provenance
5963
addProvenance x (NCited p v) = NCited (x : p) v
6064

61-
class HasCitations1 m v f where
62-
citations1 :: f a -> [Provenance m v]
63-
addProvenance1 :: Provenance m v -> f a -> f a
64-
6565
instance HasCitations1 m v f
6666
=> HasCitations m v (NValue' t f m a) where
6767
citations (NValue' f) = citations1 f
68-
addProvenance x (NValue' f) = NValue' (addProvenance1 x f)
68+
addProvenance x (NValue' f) = NValue' $ addProvenance1 x f
6969

7070
instance (HasCitations1 m v f, HasCitations m v t)
7171
=> HasCitations m v (NValue t f m) where
7272
citations (Pure t) = citations t
7373
citations (Free v) = citations v
74-
addProvenance x (Pure t) = Pure (addProvenance x t)
75-
addProvenance x (Free v) = Free (addProvenance x v)
74+
addProvenance x (Pure t) = Pure $ addProvenance x t
75+
addProvenance x (Free v) = Free $ addProvenance x v

src/Nix/Cited/Basic.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ newtype Cited t f m a = Cited { getCited :: NCited m (NValue t f m) a }
4141

4242
instance HasCitations1 m (NValue t f m) (Cited t f m) where
4343
citations1 (Cited c) = citations c
44-
addProvenance1 x (Cited c) = Cited (addProvenance x c)
44+
addProvenance1 x (Cited c) = Cited $ addProvenance x c
4545

4646
instance ( Has e Options
4747
, Framed e m
@@ -58,7 +58,7 @@ instance ( Has e Options
5858
opts :: Options <- asks (view hasLens)
5959

6060
bool
61-
(fmap (Cited . NCited mempty) . thunk $ mv)
61+
(Cited . NCited mempty <$> thunk mv)
6262
(do
6363
frames :: Frames <- asks (view hasLens)
6464

@@ -72,7 +72,7 @@ instance ( Has e Options
7272
go _ = mempty
7373
ps = concatMap (go . frame) frames
7474

75-
fmap (Cited . NCited ps) . thunk $ mv
75+
Cited . NCited ps <$> thunk mv
7676
)
7777
(thunks opts)
7878

src/Nix/Effects/Derivation.hs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ derivationParser = do
199199
_ <- ")"
200200
eof
201201

202-
let outputs = Map.fromList $ fmap (\(a, b, _, _) -> (a, b)) fullOutputs
202+
let outputs = Map.fromList $ (\(a, b, _, _) -> (a, b)) <$> fullOutputs
203203
let (mFixed, hashMode) = parseFixed fullOutputs
204204
let name = "" -- FIXME (extract from file path ?)
205205
let useJson = ["__json"] == Map.keys env
@@ -239,7 +239,8 @@ derivationParser = do
239239

240240

241241
defaultDerivationStrict :: forall e t f m b. (MonadNix e t f m, MonadState (b, MS.HashMap Text Text) m) => NValue t f m -> m (NValue t f m)
242-
defaultDerivationStrict = fromValue @(AttrSet (NValue t f m)) >=> \s -> do
242+
defaultDerivationStrict val = do
243+
s <- fromValue @(AttrSet (NValue t f m)) val
243244
(drv, ctx) <- runWithStringContextT' $ buildDerivationWithContext s
244245
drvName <- makeStorePathName $ name drv
245246
let inputs = toStorePaths ctx
@@ -270,9 +271,9 @@ defaultDerivationStrict = fromValue @(AttrSet (NValue t f m)) >=> \s -> do
270271

271272
-- Memoize here, as it may be our last chance in case of readonly stores.
272273
drvHash <- Store.encodeInBase Store.Base16 <$> hashDerivationModulo drv'
273-
modify (second (MS.insert drvPath drvHash))
274+
modify $ second $ MS.insert drvPath drvHash
274275

275-
let outputsWithContext = Map.mapWithKey (\out path -> makeNixStringWithSingletonContext path (StringContext drvPath (DerivationOutput out))) (outputs drv')
276+
let outputsWithContext = Map.mapWithKey (\out path -> makeNixStringWithSingletonContext path (StringContext drvPath $ DerivationOutput out)) (outputs drv')
276277
drvPathWithContext = makeNixStringWithSingletonContext drvPath (StringContext drvPath AllOutputs)
277278
attrSet = M.map nvStr $ M.fromList $ ("drvPath", drvPathWithContext): Map.toList outputsWithContext
278279
-- TODO: Add location information for all the entries.
@@ -303,18 +304,18 @@ defaultDerivationStrict = fromValue @(AttrSet (NValue t f m)) >=> \s -> do
303304
buildDerivationWithContext :: forall e t f m. (MonadNix e t f m) => AttrSet (NValue t f m) -> WithStringContextT m Derivation
304305
buildDerivationWithContext drvAttrs = do
305306
-- Parse name first, so we can add an informative frame
306-
drvName <- getAttr "name" $ extractNixString >=> assertDrvStoreName
307+
drvName <- getAttr "name" $ assertDrvStoreName <=< extractNixString
307308
withFrame' Info (ErrorCall $ "While evaluating derivation " <> show drvName) $ do
308309

309310
useJson <- getAttrOr "__structuredAttrs" False pure
310311
ignoreNulls <- getAttrOr "__ignoreNulls" False pure
311312

312-
args <- getAttrOr "args" mempty $ traverse (fromValue' >=> extractNixString)
313+
args <- getAttrOr "args" mempty $ traverse (extractNixString <=< fromValue')
313314
builder <- getAttr "builder" extractNixString
314-
platform <- getAttr "system" $ extractNoCtx >=> assertNonNull
315-
mHash <- getAttrOr "outputHash" mempty $ extractNoCtx >=> (pure . pure)
316-
hashMode <- getAttrOr "outputHashMode" Flat $ extractNoCtx >=> parseHashMode
317-
outputs <- getAttrOr "outputs" ["out"] $ traverse (fromValue' >=> extractNoCtx)
315+
platform <- getAttr "system" $ assertNonNull <=< extractNoCtx
316+
mHash <- getAttrOr "outputHash" mempty $ (pure . pure) <=< extractNoCtx
317+
hashMode <- getAttrOr "outputHashMode" Flat $ parseHashMode <=< extractNoCtx
318+
outputs <- getAttrOr "outputs" ["out"] $ traverse (extractNoCtx <=< fromValue')
318319

319320
mFixedOutput <-
320321
maybe
@@ -356,7 +357,7 @@ buildDerivationWithContext drvAttrs = do
356357

357358
pure $ Derivation { platform, builder, args, env, hashMode, useJson
358359
, name = drvName
359-
, outputs = Map.fromList $ fmap (, mempty) outputs
360+
, outputs = Map.fromList $ (, mempty) <$> outputs
360361
, mFixed = mFixedOutput
361362
, inputs = (mempty, mempty) -- stub for now
362363
}

src/Nix/Eval.hs

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ eval (NAbs params body) = do
172172
scope <- currentScopes :: m (Scopes m v)
173173
evalAbs params $ \arg k -> withScopes scope $ do
174174
args <- buildArgument params arg
175-
pushScope args (k (withScopes scope . inform <$> args) body)
175+
pushScope args $ k (withScopes scope . inform <$> args) body
176176

177177
eval (NSynHole name) = synHole name
178178

@@ -186,7 +186,7 @@ evalWithAttrSet aset body = do
186186
-- computed once.
187187
scope <- currentScopes :: m (Scopes m v)
188188
s <- defer $ withScopes scope aset
189-
let s' = (fmap fst . fromValue @(AttrSet v, AttrSet SourcePos)) =<< demand s
189+
let s' = fst <$> (fromValue @(AttrSet v, AttrSet SourcePos) =<< demand s)
190190

191191
pushWeakScope s' body
192192

@@ -282,15 +282,15 @@ evalBinds recursive binds =
282282
res <-
283283
bool
284284
(traverse mkThunk s)
285-
(loebM (encapsulate <$> s))
285+
(loebM $ encapsulate <$> s)
286286
recursive
287287

288288
pure (res, p)
289289

290290
where
291291
mkThunk = defer . withScopes scope
292292

293-
encapsulate f attrs = mkThunk . pushScope attrs $ f
293+
encapsulate f attrs = mkThunk $ pushScope attrs f
294294

295295
insert (m, p) (path, pos, value) = attrSetAlter path pos m p value
296296

@@ -305,19 +305,15 @@ evalBinds recursive binds =
305305
, fromMaybe pos (M.lookup k p')
306306
, demand v
307307
)
308-
) <$>
309-
M.toList o'
308+
) <$> M.toList o'
310309

311310
applyBindToAdt _ (NamedVar pathExpr finalValue pos) =
312-
do
313-
fmap
314-
(\case
315-
-- When there are no path segments, e.g. `${null} = 5;`, we don't
316-
-- bind anything
317-
([], _, _) -> mempty
318-
result -> [result]
319-
)
320-
(processAttrSetKeys pathExpr)
311+
(\case
312+
-- When there are no path segments, e.g. `${null} = 5;`, we don't
313+
-- bind anything
314+
([], _, _) -> mempty
315+
result -> [result]
316+
) <$> processAttrSetKeys pathExpr
321317

322318
where
323319
processAttrSetKeys :: NAttrPath (m v) -> m ([Text], SourcePos, m v)
@@ -496,12 +492,12 @@ buildArgument params arg =
496492
This _
497493
| isVariadic -> Nothing
498494
| otherwise -> pure $ const $ evalError @v $ ErrorCall $ "Unexpected parameter: " <> show k
499-
These x _ -> pure (const (pure x))
495+
These x _ -> pure $ const $ pure x
500496

501497
addSourcePositions
502498
:: (MonadReader e m, Has e SrcSpan) => Transform NExprLocF (m a)
503499
addSourcePositions f v@(Fix (Compose (Ann ann _))) =
504-
local (set hasLens ann) (f v)
500+
local (set hasLens ann) $ f v
505501

506502
addStackFrames
507503
:: forall v e m a
@@ -524,4 +520,4 @@ framedEvalExprLoc
524520
=> NExprLoc
525521
-> m v
526522
framedEvalExprLoc =
527-
adi (eval . annotated . getCompose) (addStackFrames @v . addSourcePositions)
523+
adi (eval . annotated . getCompose) $ addStackFrames @v . addSourcePositions

src/Nix/Normal.hs

Lines changed: 69 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
{-# LANGUAGE ScopedTypeVariables #-}
77
{-# LANGUAGE TypeApplications #-}
88
{-# LANGUAGE TypeFamilies #-}
9+
{-# LANGUAGE RankNTypes #-}
910

1011
-- | Code for normalization (reduction into a normal form) of Nix expressions.
1112
-- Nix language allows recursion, so some expressions do not converge.
@@ -15,7 +16,9 @@ module Nix.Normal where
1516
import Prelude hiding ( force )
1617
import Nix.Utils
1718
import Control.Monad.Free ( Free(..) )
18-
import Data.Set
19+
import Data.Set ( member
20+
, insert
21+
)
1922
import Nix.Cited
2023
import Nix.Frames
2124
import Nix.String
@@ -56,9 +59,7 @@ normalizeValue v = run $ iterNValueM run go (fmap Free . sequenceNValue' run) v
5659
bool
5760
(do
5861
i <- ask
59-
when (i > 2000)
60-
$ fail "Exceeded maximum normalization depth of 2000 levels"
61-
-- 2021-02-22: NOTE: `normalizeValue` should be adopted to work without fliping of the force (f)
62+
when (i > 2000) $ fail "Exceeded maximum normalization depth of 2000 levels"
6263
lifted (lifted $ \f -> f =<< force t) $ local succ . k
6364
)
6465
(pure $ pure t)
@@ -67,10 +68,57 @@ normalizeValue v = run $ iterNValueM run go (fmap Free . sequenceNValue' run) v
6768
seen t = do
6869
let tid = thunkId t
6970
lift $ do
70-
res <- gets (member tid)
71-
unless res $ modify (insert tid)
71+
res <- gets $ member tid
72+
unless res $ modify $ insert tid
7273
pure res
7374

75+
-- 2021-05-09: NOTE: This seems a bit excessive. If these functorial versions are not used for recursion schemes - just free from it.
76+
-- | Normalization HOF (functorial) version of @normalizeValue@. Accepts the special thunk operating/forcing/nirmalizing function & internalizes it.
77+
normalizeValueF
78+
:: forall e t m f
79+
. ( Framed e m
80+
, MonadThunk t m (NValue t f m)
81+
, MonadDataErrorContext t f m
82+
, Ord (ThunkId m)
83+
)
84+
=> (forall r . t -> (NValue t f m -> m r) -> m r)
85+
-> NValue t f m
86+
-> m (NValue t f m)
87+
normalizeValueF f = run . iterNValueM run go (fmap Free . sequenceNValue' run)
88+
where
89+
start = 0 :: Int
90+
table = mempty
91+
92+
run :: ReaderT Int (StateT (Set (ThunkId m)) m) r -> m r
93+
run = (`evalStateT` table) . (`runReaderT` start)
94+
95+
go
96+
:: t
97+
-> ( NValue t f m
98+
-> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m)
99+
)
100+
-> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m)
101+
go t k = do
102+
b <- seen t
103+
bool
104+
(do
105+
i <- ask
106+
when (i > 2000) $ fail "Exceeded maximum normalization depth of 2000 levels"
107+
lifted (lifted $ f t) $ local succ . k
108+
)
109+
(pure $ pure t)
110+
b
111+
112+
seen t = do
113+
let tid = thunkId t
114+
lift $ do
115+
res <- gets $ member tid
116+
unless res $ modify $ insert tid
117+
pure res
118+
119+
-- | Normalize value.
120+
-- Detect cycles.
121+
-- If cycles were detected - put a stub on them.
74122
normalForm
75123
:: ( Framed e m
76124
, MonadThunk t m (NValue t f m)
@@ -83,6 +131,7 @@ normalForm
83131
-> m (NValue t f m)
84132
normalForm t = stubCycles <$> normalizeValue t
85133

134+
-- | Monadic context of the result.
86135
normalForm_
87136
:: ( Framed e m
88137
, MonadThunk t m (NValue t f m)
@@ -91,8 +140,9 @@ normalForm_
91140
)
92141
=> NValue t f m
93142
-> m ()
94-
normalForm_ t = void (normalizeValue t)
143+
normalForm_ t = void $ normalizeValue t
95144

145+
-- | Detect cycles & stub them.
96146
stubCycles
97147
:: forall t f m
98148
. ( MonadDataContext f m
@@ -101,12 +151,17 @@ stubCycles
101151
)
102152
=> NValue t f m
103153
-> NValue t f m
104-
stubCycles = flip iterNValue Free $ \t _ ->
105-
Free
106-
$ NValue'
107-
$ Prelude.foldr (addProvenance1 @m @(NValue t f m)) cyc
108-
$ reverse
109-
$ citations @m @(NValue t f m) t
154+
stubCycles =
155+
iterNValue
156+
(\t _ ->
157+
Free $
158+
NValue' $
159+
foldr
160+
(addProvenance1 @m @(NValue t f m))
161+
cyc
162+
(reverse $ citations @m @(NValue t f m) t)
163+
)
164+
Free
110165
where
111166
Free (NValue' cyc) = opaque
112167

@@ -122,7 +177,7 @@ removeEffects =
122177
(fmap Free . sequenceNValue' id)
123178

124179
opaque :: Applicative f => NValue t f m
125-
opaque = nvStr $ makeNixStringWithoutContext "<expr>"
180+
opaque = nvStr $ makeNixStringWithoutContext "<cycle>"
126181

127182
dethunk
128183
:: (MonadThunk t m (NValue t f m), MonadDataContext f m)

0 commit comments

Comments
 (0)