diff --git a/README-design.md b/README-design.md index 92f16a3..c0bf0e9 100644 --- a/README-design.md +++ b/README-design.md @@ -41,15 +41,3 @@ points in the code are generic over both. Having said that, I should mention that there are two different types of values: `NValue` and `NValueNF`. The former is created by evaluating an `NExpr`, and then latter by calling `normalForm` on an `NValue`. - -However, not every term can be reduced to normal form. There are cases where -Nix allows a cycle to exist in the data, so that it can printed simply as -``. To represent this, we use a simple recursive type for `NValue`, but -a `Free` construction for `NValueNF`: - - type NValueNF t f m = Free (NValue' t f m) t - -The idea here is that `Free` values are those we were able to normalize (since -it has its own terminating base cases of constants, strings, etc), while the -`Pure` thunk is the thunk we'd seen before while normalizing, indicating the -beginning of the cycle. diff --git a/hnix.cabal b/hnix.cabal index 4e2ccd4..8974ab4 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -475,6 +475,7 @@ library Nix.Utils Nix.Value Nix.Value.Equal + Nix.Value.Monad Nix.Var Nix.XML other-modules: diff --git a/src/Nix/Builtins.hs b/src/Nix/Builtins.hs index d1a2729..dbc59cb 100644 --- a/src/Nix/Builtins.hs +++ b/src/Nix/Builtins.hs @@ -126,7 +126,8 @@ withNixContext mpath action = do let ref = wrapValue @t @m @(NValue t f m) $ nvPath path pushScope (M.singleton "__cur_file" ref) action -builtins :: (MonadNix e t f m, Scoped t m) => m (Scopes m t) +builtins :: (MonadNix e t f m, Scoped (NValue t f m) m) + => m (Scopes m (NValue t f m)) builtins = do ref <- thunk $ flip nvSet M.empty <$> buildMap lst <- ([("builtins", ref)] ++) <$> topLevelBuiltins diff --git a/src/Nix/Cited.hs b/src/Nix/Cited.hs index e8e9cb8..a5f0b43 100644 --- a/src/Nix/Cited.hs +++ b/src/Nix/Cited.hs @@ -21,8 +21,8 @@ import Lens.Family2.TH import Nix.Expr.Types.Annotated import Nix.Scope -data Provenance t m v = Provenance - { _lexicalScope :: Scopes m t +data Provenance m v = Provenance + { _lexicalScope :: Scopes m v , _originExpr :: NExprLocF (Maybe v) -- ^ When calling the function x: x + 2 with argument x = 3, the -- 'originExpr' for the resulting value will be 3 + 2, while the @@ -31,34 +31,34 @@ data Provenance t m v = Provenance } deriving (Generic, Typeable, Show) -data NCited t m v a = NCited - { _provenance :: [Provenance t m v] +data NCited m v a = NCited + { _provenance :: [Provenance m v] , _cited :: a } deriving (Generic, Typeable, Functor, Foldable, Traversable, Show) -instance Applicative (NCited t m v) where +instance Applicative (NCited m v) where pure = NCited [] NCited xs f <*> NCited ys x = NCited (xs <> ys) (f x) -instance Comonad (NCited t m v) where +instance Comonad (NCited m v) where duplicate p = NCited (_provenance p) p extract = _cited -instance ComonadEnv [Provenance t m v] (NCited t m v) where +instance ComonadEnv [Provenance m v] (NCited m v) where ask = _provenance $(makeLenses ''Provenance) $(makeLenses ''NCited) -class HasCitations t m v a where - citations :: a -> [Provenance t m v] - addProvenance :: Provenance t m v -> a -> a +class HasCitations m v a where + citations :: a -> [Provenance m v] + addProvenance :: Provenance m v -> a -> a -instance HasCitations t m v (NCited t m v a) where +instance HasCitations m v (NCited m v a) where citations = _provenance addProvenance x (NCited p v) = (NCited (x : p) v) -class HasCitations1 t m v f where - citations1 :: f a -> [Provenance t m v] - addProvenance1 :: Provenance t m v -> f a -> f a +class HasCitations1 m v f where + citations1 :: f a -> [Provenance m v] + addProvenance1 :: Provenance m v -> f a -> f a diff --git a/src/Nix/Convert.hs b/src/Nix/Convert.hs index f7590c6..1bff663 100644 --- a/src/Nix/Convert.hs +++ b/src/Nix/Convert.hs @@ -8,6 +8,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeApplications #-} @@ -27,10 +28,9 @@ module Nix.Convert where -import Control.Monad -import Control.Monad.Catch +import Control.Monad.Free import Data.ByteString -import Data.HashMap.Lazy ( HashMap ) +import Data.Fix import qualified Data.HashMap.Lazy as M import Data.Maybe import Data.Text ( Text ) @@ -44,8 +44,9 @@ import Nix.Expr.Types import Nix.Expr.Types.Annotated import Nix.Frames import Nix.String -import Nix.Thunk import Nix.Value +import Nix.Value.Monad +import Nix.Utils {- @@ -60,144 +61,104 @@ Do not add these instances back! -} +{----------------------------------------------------------------------- + FromValue + -----------------------------------------------------------------------} + class FromValue a m v where fromValue :: v -> m a fromValueMay :: v -> m (Maybe a) -type Convertible e t f m - = (Framed e m, MonadThunk t m (NValue t f m), MonadDataErrorContext t f m) +type Convertible e t f m = (Framed e m, MonadDataErrorContext t f m) -instance Convertible e t f m => FromValue () m (NValueNF t f m) where - fromValueMay = \case - NVConstantNF NNull -> pure $ Just () - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TNull v +instance (Monad m, FromValue a m v) => FromValue a m (m v) where + fromValueMay = (>>= fromValueMay) + fromValue = (>>= fromValue) -instance Convertible e t f m => FromValue () m (NValue t f m) where +instance ( Convertible e t f m + , MonadValue (NValueNF t f m) m + , FromValue a m (NValue' t f m (NValueNF t f m)) + ) + => FromValue a m (NValueNF t f m) where + fromValueMay = flip demand $ \(Fix v) -> fromValueMay v + fromValue = flip demand $ \(Fix v) -> fromValue v + +instance ( Convertible e t f m + , MonadValue (NValue t f m) m + , FromValue a m (NValue' t f m (NValue t f m)) + ) + => FromValue a m (NValue t f m) where + fromValueMay = flip demand $ \case + Pure _ -> pure Nothing + Free v -> fromValueMay v + fromValue = flip demand $ \case + Pure t -> throwError $ ForcingThunk @t @f @m t + Free v -> fromValue v + +instance (Convertible e t f m, Show r) => FromValue () m (NValue' t f m r) where fromValueMay = \case - NVConstant NNull -> pure $ Just () - _ -> pure Nothing + NVConstant' NNull -> pure $ Just () + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TNull v -instance Convertible e t f m => FromValue Bool m (NValueNF t f m) where +instance (Convertible e t f m, Show r) => FromValue Bool m (NValue' t f m r) where fromValueMay = \case - NVConstantNF (NBool b) -> pure $ Just b - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TBool v - -instance Convertible e t f m => FromValue Bool m (NValue t f m) where - fromValueMay = \case - NVConstant (NBool b) -> pure $ Just b - _ -> pure Nothing + NVConstant' (NBool b) -> pure $ Just b + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TBool v -instance Convertible e t f m => FromValue Int m (NValueNF t f m) where +instance (Convertible e t f m, Show r) => FromValue Int m (NValue' t f m r) where fromValueMay = \case - NVConstantNF (NInt b) -> pure $ Just (fromInteger b) - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TInt v - -instance Convertible e t f m => FromValue Int m (NValue t f m) where - fromValueMay = \case - NVConstant (NInt b) -> pure $ Just (fromInteger b) - _ -> pure Nothing + NVConstant' (NInt b) -> pure $ Just (fromInteger b) + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TInt v -instance Convertible e t f m => FromValue Integer m (NValueNF t f m) where +instance (Convertible e t f m, Show r) => FromValue Integer m (NValue' t f m r) where fromValueMay = \case - NVConstantNF (NInt b) -> pure $ Just b - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TInt v - -instance Convertible e t f m => FromValue Integer m (NValue t f m) where - fromValueMay = \case - NVConstant (NInt b) -> pure $ Just b - _ -> pure Nothing + NVConstant' (NInt b) -> pure $ Just b + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TInt v -instance Convertible e t f m => FromValue Float m (NValueNF t f m) where +instance (Convertible e t f m, Show r) => FromValue Float m (NValue' t f m r) where fromValueMay = \case - NVConstantNF (NFloat b) -> pure $ Just b - NVConstantNF (NInt i) -> pure $ Just (fromInteger i) - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TFloat v - -instance Convertible e t f m => FromValue Float m (NValue t f m) where - fromValueMay = \case - NVConstant (NFloat b) -> pure $ Just b - NVConstant (NInt i) -> pure $ Just (fromInteger i) - _ -> pure Nothing + NVConstant' (NFloat b) -> pure $ Just b + NVConstant' (NInt i) -> pure $ Just (fromInteger i) + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TFloat v -instance (Convertible e t f m, MonadEffects t f m) - => FromValue NixString m (NValueNF t f m) where +instance (Convertible e t f m, Show r, MonadEffects t f m, + FromValue NixString m r) + => FromValue NixString m (NValue' t f m r) where fromValueMay = \case - NVStrNF ns -> pure $ Just ns - NVPathNF p -> + NVStr' ns -> pure $ Just ns + NVPath' p -> Just . hackyMakeNixStringWithoutContext . Text.pack . unStorePath <$> addPath p - NVSetNF s _ -> case M.lookup "outPath" s of + NVSet' s _ -> case M.lookup "outPath" s of Nothing -> pure Nothing Just p -> fromValueMay p _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF (TString NoContext) v - -instance (Convertible e t f m, MonadEffects t f m) - => FromValue NixString m (NValue t f m) where - fromValueMay = \case - NVStr ns -> pure $ Just ns - NVPath p -> - Just - . hackyMakeNixStringWithoutContext - . Text.pack - . unStorePath - <$> addPath p - NVSet s _ -> case M.lookup "outPath" s of - Nothing -> pure Nothing - Just p -> force p fromValueMay - _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation (TString NoContext) v -instance Convertible e t f m - => FromValue ByteString m (NValueNF t f m) where +instance (Convertible e t f m, Show r) + => FromValue ByteString m (NValue' t f m r) where fromValueMay = \case - NVStrNF ns -> pure $ encodeUtf8 <$> hackyGetStringNoContext ns - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF (TString NoContext) v - -instance Convertible e t f m - => FromValue ByteString m (NValue t f m) where - fromValueMay = \case - NVStr ns -> pure $ encodeUtf8 <$> hackyGetStringNoContext ns + NVStr' ns -> pure $ encodeUtf8 <$> hackyGetStringNoContext ns _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b @@ -206,191 +167,125 @@ instance Convertible e t f m newtype Path = Path { getPath :: FilePath } deriving Show -instance Convertible e t f m => FromValue Path m (NValueNF t f m) where +instance (Convertible e t f m, Show r, FromValue Path m r) + => FromValue Path m (NValue' t f m r) where fromValueMay = \case - NVPathNF p -> pure $ Just (Path p) - NVStrNF ns -> pure $ Path . Text.unpack <$> hackyGetStringNoContext ns - NVSetNF s _ -> case M.lookup "outPath" s of + NVPath' p -> pure $ Just (Path p) + NVStr' ns -> pure $ Path . Text.unpack <$> hackyGetStringNoContext ns + NVSet' s _ -> case M.lookup "outPath" s of Nothing -> pure Nothing Just p -> fromValueMay @Path p _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TPath v - -instance Convertible e t f m => FromValue Path m (NValue t f m) where - fromValueMay = \case - NVPath p -> pure $ Just (Path p) - NVStr ns -> pure $ Path . Text.unpack <$> hackyGetStringNoContext ns - NVSet s _ -> case M.lookup "outPath" s of - Nothing -> pure Nothing - Just p -> force p $ fromValueMay @Path - _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TPath v -instance (Convertible e t f m, FromValue a m (NValueNF t f m), Show a) - => FromValue [a] m (NValueNF t f m) where +instance (Convertible e t f m, Show r) + => FromValue [r] m (NValue' t f m r) where fromValueMay = \case - NVListNF l -> sequence <$> traverse fromValueMay l - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TList v - -instance Convertible e t f m => FromValue [t] m (NValue t f m) where - fromValueMay = \case - NVList l -> pure $ Just l - _ -> pure Nothing + NVList' l -> pure $ Just l + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TList v -instance Convertible e t f m - => FromValue (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where +instance (Convertible e t f m, Show r) + => FromValue (AttrSet r) m (NValue' t f m r) where fromValueMay = \case - NVSetNF s _ -> pure $ Just s - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TSet v - -instance Convertible e t f m - => FromValue (HashMap Text t) m (NValue t f m) where - fromValueMay = \case - NVSet s _ -> pure $ Just s - _ -> pure Nothing + NVSet' s _ -> pure $ Just s + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TSet v -instance Convertible e t f m - => FromValue (HashMap Text (NValueNF t f m), - HashMap Text SourcePos) m (NValueNF t f m) where +instance (Convertible e t f m, Show r) + => FromValue (AttrSet r, AttrSet SourcePos) m (NValue' t f m r) where fromValueMay = \case - NVSetNF s p -> pure $ Just (s, p) - _ -> pure Nothing - fromValue v = fromValueMay v >>= \case - Just b -> pure b - _ -> throwError $ ExpectationNF TSet v - -instance Convertible e t f m - => FromValue (HashMap Text t, - HashMap Text SourcePos) m (NValue t f m) where - fromValueMay = \case - NVSet s p -> pure $ Just (s, p) - _ -> pure Nothing + NVSet' s p -> pure $ Just (s, p) + _ -> pure Nothing fromValue v = fromValueMay v >>= \case Just b -> pure b _ -> throwError $ Expectation TSet v -instance (Monad m, FromValue a m v) => FromValue a m (m v) where - fromValueMay = (>>= fromValueMay) - fromValue = (>>= fromValue) +{----------------------------------------------------------------------- + ToValue + -----------------------------------------------------------------------} class ToValue a m v where toValue :: a -> m v -instance Convertible e t f m => ToValue () m (NValueNF t f m) where - toValue _ = pure . nvConstantNF $ NNull +instance (Monad m, ToValue a m v) => ToValue a m (m v) where + toValue = pure . toValue -instance Convertible e t f m => ToValue () m (NValue t f m) where - toValue _ = pure . nvConstant $ NNull +instance (Convertible e t f m, forall r. Show r => ToValue a m (NValue' t f m r)) + => ToValue a m (NValueNF t f m) where + toValue = fmap Fix . toValue -instance Convertible e t f m => ToValue Bool m (NValueNF t f m) where - toValue = pure . nvConstantNF . NBool +instance (Convertible e t f m, forall r. Show r => ToValue a m (NValue' t f m r)) + => ToValue a m (NValue t f m) where + toValue = fmap Free . toValue -instance Convertible e t f m => ToValue Bool m (NValue t f m) where - toValue = pure . nvConstant . NBool +instance Convertible e t f m => ToValue () m (NValue' t f m r) where + toValue _ = pure . nvConstant' $ NNull -instance Convertible e t f m => ToValue Int m (NValueNF t f m) where - toValue = pure . nvConstantNF . NInt . toInteger +instance Convertible e t f m => ToValue Bool m (NValue' t f m r) where + toValue = pure . nvConstant' . NBool -instance Convertible e t f m => ToValue Int m (NValue t f m) where - toValue = pure . nvConstant . NInt . toInteger +instance Convertible e t f m => ToValue Int m (NValue' t f m r) where + toValue = pure . nvConstant' . NInt . toInteger -instance Convertible e t f m => ToValue Integer m (NValueNF t f m) where - toValue = pure . nvConstantNF . NInt +instance Convertible e t f m => ToValue Integer m (NValue' t f m r) where + toValue = pure . nvConstant' . NInt -instance Convertible e t f m => ToValue Integer m (NValue t f m) where - toValue = pure . nvConstant . NInt +instance Convertible e t f m => ToValue Float m (NValue' t f m r) where + toValue = pure . nvConstant' . NFloat -instance Convertible e t f m => ToValue Float m (NValueNF t f m) where - toValue = pure . nvConstantNF . NFloat +instance Convertible e t f m => ToValue NixString m (NValue' t f m r) where + toValue = pure . nvStr' -instance Convertible e t f m => ToValue Float m (NValue t f m) where - toValue = pure . nvConstant . NFloat +instance Convertible e t f m => ToValue ByteString m (NValue' t f m r) where + toValue = pure . nvStr' . hackyMakeNixStringWithoutContext . decodeUtf8 -instance Convertible e t f m => ToValue NixString m (NValueNF t f m) where - toValue = pure . nvStrNF +instance Convertible e t f m => ToValue Path m (NValue' t f m r) where + toValue = pure . nvPath' . getPath -instance Convertible e t f m => ToValue NixString m (NValue t f m) where - toValue = pure . nvStr - -instance Convertible e t f m => ToValue ByteString m (NValueNF t f m) where - toValue = pure . nvStrNF . hackyMakeNixStringWithoutContext . decodeUtf8 - -instance Convertible e t f m => ToValue ByteString m (NValue t f m) where - toValue = pure . nvStr . hackyMakeNixStringWithoutContext . decodeUtf8 - -instance Convertible e t f m => ToValue Path m (NValueNF t f m) where - toValue = pure . nvPathNF . getPath - -instance Convertible e t f m => ToValue Path m (NValue t f m) where - toValue = pure . nvPath . getPath - -instance Convertible e t f m => ToValue StorePath m (NValueNF t f m) where +instance Convertible e t f m => ToValue StorePath m (NValue' t f m r) where toValue = toValue . Path . unStorePath -instance Convertible e t f m => ToValue StorePath m (NValue t f m) where - toValue = toValue . Path . unStorePath - -instance Convertible e t f m => ToValue SourcePos m (NValue t f m) where +instance ( Convertible e t f m + , ToValue NixString m r + , ToValue Int m r + ) + => ToValue SourcePos m (NValue' t f m r) where toValue (SourcePos f l c) = do - f' <- pure $ nvStr $ principledMakeNixStringWithoutContext (Text.pack f) + f' <- toValue (principledMakeNixStringWithoutContext (Text.pack f)) l' <- toValue (unPos l) c' <- toValue (unPos c) let pos = M.fromList - [ ("file" :: Text, wrapValue f') - , ("line" , wrapValue l') - , ("column" , wrapValue c') + [ ("file" :: Text, f') + , ("line" , l') + , ("column" , c') ] - pure $ nvSet pos mempty + pure $ nvSet' pos mempty -instance (Convertible e t f m, ToValue a m (NValueNF t f m)) - => ToValue [a] m (NValueNF t f m) where - toValue = fmap nvListNF . traverse toValue +instance Convertible e t f m => ToValue [r] m (NValue' t f m r) where + toValue = pure . nvList' -instance Convertible e t f m => ToValue [t] m (NValue t f m) where - toValue = pure . nvList +instance Convertible e t f m => ToValue (AttrSet r) m (NValue' t f m r) where + toValue = pure . flip nvSet' M.empty instance Convertible e t f m - => ToValue (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where - toValue = pure . flip nvSetNF M.empty + => ToValue (AttrSet r, AttrSet SourcePos) m (NValue' t f m r) where + toValue (s, p) = pure $ nvSet' s p -instance Convertible e t f m => ToValue (HashMap Text t) m (NValue t f m) where - toValue = pure . flip nvSet M.empty - -instance Convertible e t f m => ToValue (HashMap Text (NValueNF t f m), - HashMap Text SourcePos) m (NValueNF t f m) where - toValue (s, p) = pure $ nvSetNF s p - -instance Convertible e t f m => ToValue (HashMap Text t, - HashMap Text SourcePos) m (NValue t f m) where - toValue (s, p) = pure $ nvSet s p - -instance Convertible e t f m => ToValue Bool m (NExprF r) where - toValue = pure . NConstant . NBool - -instance Convertible e t f m => ToValue () m (NExprF r) where - toValue _ = pure . NConstant $ NNull - -instance ( MonadThunk t m (NValue t f m) +instance ( MonadValue (NValue t f m) m , MonadDataErrorContext t f m , Framed e m + , ToValue NixString m r + , ToValue Bool m r + , ToValue [r] m r ) - => ToValue NixLikeContextValue m (NValue t f m) where + => ToValue NixLikeContextValue m (NValue' t f m r) where toValue nlcv = do path <- if nlcvPath nlcv then Just <$> toValue True else return Nothing allOutputs <- if nlcvAllOutputs nlcv @@ -399,130 +294,18 @@ instance ( MonadThunk t m (NValue t f m) outputs <- do let outputs = fmap principledMakeNixStringWithoutContext $ nlcvOutputs nlcv - outputsM :: [NValue t f m] <- traverse toValue outputs - let ts :: [t] = fmap wrapValue outputsM + ts :: [r] <- traverse toValue outputs case ts of [] -> return Nothing _ -> Just <$> toValue ts - pure $ flip nvSet M.empty $ M.fromList $ catMaybes - [ (\p -> ("path", wrapValue p)) <$> path - , (\ao -> ("allOutputs", wrapValue ao)) <$> allOutputs - , (\os -> ("outputs", wrapValue os)) <$> outputs + pure $ flip nvSet' M.empty $ M.fromList $ catMaybes + [ (\p -> ("path", p)) <$> path + , (\ao -> ("allOutputs", ao)) <$> allOutputs + , (\os -> ("outputs", os)) <$> outputs ] -whileForcingThunk - :: forall t f m s e r . (Exception s, Convertible e t f m) => s -> m r -> m r -whileForcingThunk frame = - withFrame Debug (ForcingThunk @t @f @m) . withFrame Debug frame +instance Convertible e t f m => ToValue () m (NExprF r) where + toValue _ = pure . NConstant $ NNull -class FromNix a m v where - fromNix :: v -> m a - default fromNix :: FromValue a m v => v -> m a - fromNix = fromValue - - fromNixMay :: v -> m (Maybe a) - default fromNixMay :: FromValue a m v => v -> m (Maybe a) - fromNixMay = fromValueMay - -instance (Convertible e t f m, FromNix a m (NValue t f m)) - => FromNix [a] m (NValue t f m) where - fromNixMay = \case - NVList l -> sequence <$> traverse (`force` fromNixMay) l - _ -> pure Nothing - fromNix v = fromNixMay v >>= \case - Just b -> pure b - _ -> throwError $ Expectation TList v - -instance (Convertible e t f m, FromNix a m (NValue t f m)) - => FromNix (HashMap Text a) m (NValue t f m) where - fromNixMay = \case - NVSet s _ -> sequence <$> traverse (`force` fromNixMay) s - _ -> pure Nothing - fromNix v = fromNixMay v >>= \case - Just b -> pure b - _ -> throwError $ Expectation TSet v - -instance Convertible e t f m => FromNix () m (NValueNF t f m) where -instance Convertible e t f m => FromNix () m (NValue t f m) where -instance Convertible e t f m => FromNix Bool m (NValueNF t f m) where -instance Convertible e t f m => FromNix Bool m (NValue t f m) where -instance Convertible e t f m => FromNix Int m (NValueNF t f m) where -instance Convertible e t f m => FromNix Int m (NValue t f m) where -instance Convertible e t f m => FromNix Integer m (NValueNF t f m) where -instance Convertible e t f m => FromNix Integer m (NValue t f m) where -instance Convertible e t f m => FromNix Float m (NValueNF t f m) where -instance Convertible e t f m => FromNix Float m (NValue t f m) where -instance (Convertible e t f m, MonadEffects t f m) - => FromNix NixString m (NValueNF t f m) where -instance (Convertible e t f m, MonadEffects t f m) - => FromNix NixString m (NValue t f m) where -instance Convertible e t f m => FromNix ByteString m (NValueNF t f m) where -instance Convertible e t f m => FromNix ByteString m (NValue t f m) where -instance Convertible e t f m => FromNix Path m (NValueNF t f m) where -instance Convertible e t f m => FromNix Path m (NValue t f m) where -instance (Convertible e t f m, FromValue a m (NValueNF t f m), Show a) - => FromNix [a] m (NValueNF t f m) where -instance Convertible e t f m - => FromNix (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where -instance Convertible e t f m - => FromNix (HashMap Text (NValueNF t f m), - HashMap Text SourcePos) m (NValueNF t f m) where -instance Convertible e t f m - => FromNix (HashMap Text t, HashMap Text SourcePos) m (NValue t f m) where - -instance (Monad m, FromNix a m v) => FromNix a m (m v) where - fromNixMay = (>>= fromNixMay) - fromNix = (>>= fromNix) - -class ToNix a m v where - toNix :: a -> m v - default toNix :: ToValue a m v => a -> m v - toNix = toValue - -instance (Convertible e t f m, ToNix a m (NValue t f m)) - => ToNix [a] m (NValue t f m) where - toNix = fmap nvList . traverse (thunk . go) - where - go = - (\v -> whileForcingThunk @t @f @m (ConcerningValue v) (pure v)) <=< toNix - -instance (Convertible e t f m, ToNix a m (NValue t f m)) - => ToNix (HashMap Text a) m (NValue t f m) where - toNix = fmap (flip nvSet M.empty) . traverse (thunk . go) - where - go = - (\v -> whileForcingThunk @t @f @m (ConcerningValue v) (pure v)) <=< toNix - -instance Convertible e t f m => ToNix () m (NValueNF t f m) where -instance Convertible e t f m => ToNix () m (NValue t f m) where -instance Convertible e t f m => ToNix Bool m (NValueNF t f m) where -instance Convertible e t f m => ToNix Bool m (NValue t f m) where -instance Convertible e t f m => ToNix Int m (NValueNF t f m) where -instance Convertible e t f m => ToNix Int m (NValue t f m) where -instance Convertible e t f m => ToNix Integer m (NValueNF t f m) where -instance Convertible e t f m => ToNix Integer m (NValue t f m) where -instance Convertible e t f m => ToNix Float m (NValueNF t f m) where -instance Convertible e t f m => ToNix Float m (NValue t f m) where -instance Convertible e t f m => ToNix NixString m (NValueNF t f m) where -instance Convertible e t f m => ToNix NixString m (NValue t f m) where -instance Convertible e t f m => ToNix ByteString m (NValueNF t f m) where -instance Convertible e t f m => ToNix ByteString m (NValue t f m) where -instance Convertible e t f m => ToNix Path m (NValueNF t f m) where -instance Convertible e t f m => ToNix Path m (NValue t f m) where -instance Convertible e t f m - => ToNix (HashMap Text (NValueNF t f m)) m (NValueNF t f m) where -instance Convertible e t f m - => ToNix (HashMap Text (NValueNF t f m), - HashMap Text SourcePos) m (NValueNF t f m) where -instance Convertible e t f m - => ToNix (HashMap Text t, HashMap Text SourcePos) m (NValue t f m) where - -instance Convertible e t f m => ToNix Bool m (NExprF r) where - toNix = pure . NConstant . NBool - -instance Convertible e t f m => ToNix () m (NExprF r) where - toNix _ = pure $ NConstant NNull - -instance (Convertible e t f m, ToNix a m (NValueNF t f m)) - => ToNix [a] m (NValueNF t f m) where - toNix = fmap nvListNF . traverse toNix +instance Convertible e t f m => ToValue Bool m (NExprF r) where + toValue = pure . NConstant . NBool diff --git a/src/Nix/Effects.hs b/src/Nix/Effects.hs index 564605e..aeb9dd2 100644 --- a/src/Nix/Effects.hs +++ b/src/Nix/Effects.hs @@ -51,7 +51,7 @@ class (MonadFile m, -- | Having an explicit list of sets corresponding to the NIX_PATH -- and a file path try to find an existing path - findPath :: [t] -> FilePath -> m FilePath + findPath :: [NValue t f m] -> FilePath -> m FilePath importPath :: FilePath -> m (NValue t f m) pathToDefaultNix :: FilePath -> m FilePath diff --git a/src/Nix/Eval.hs b/src/Nix/Eval.hs index c1a3cf1..ab0919c 100644 --- a/src/Nix/Eval.hs +++ b/src/Nix/Eval.hs @@ -38,81 +38,89 @@ import Nix.Frames import Nix.String import Nix.Scope import Nix.Strings ( runAntiquoted ) -import Nix.Thunk import Nix.Utils +import Nix.Value.Monad + +-- instance MonadThunk t m (NValue t f m) => MonadValue (NValue t f m) m where +-- defer = fmap Pure . thunk +-- demand (Pure t) f = force t f +-- demand v@(Free _) f = f v class (Show v, Monad m) => MonadEval v m where - freeVariable :: Text -> m v - synHole :: Text -> m v - attrMissing :: NonEmpty Text -> Maybe v -> m v - evaledSym :: Text -> v -> m v - evalCurPos :: m v - evalConstant :: NAtom -> m v - evalString :: NString (m v) -> m v - evalLiteralPath :: FilePath -> m v - evalEnvPath :: FilePath -> m v - evalUnary :: NUnaryOp -> v -> m v - evalBinary :: NBinaryOp -> v -> m v -> m v - -- ^ The second argument is an action because operators such as boolean && - -- and || may not evaluate the second argument. - evalWith :: m v -> m v -> m v - evalIf :: v -> m v -> m v -> m v - evalAssert :: v -> m v -> m v - evalApp :: v -> m v -> m v - evalAbs :: Params (m v) - -> (forall a. m v -> (AttrSet (m v) -> m v -> m (a, v)) -> m (a, v)) - -> m v + freeVariable :: Text -> m v + synHole :: Text -> m v + attrMissing :: NonEmpty Text -> Maybe v -> m v + evaledSym :: Text -> v -> m v + evalCurPos :: m v + evalConstant :: NAtom -> m v + evalString :: NString (m v) -> m v + evalLiteralPath :: FilePath -> m v + evalEnvPath :: FilePath -> m v + evalUnary :: NUnaryOp -> v -> m v + evalBinary :: NBinaryOp -> v -> m v -> m v + -- ^ The second argument is an action because operators such as boolean && + -- and || may not evaluate the second argument. + evalWith :: m v -> m v -> m v + evalIf :: v -> m v -> m v -> m v + evalAssert :: v -> m v -> m v + evalApp :: v -> m v -> m v + evalAbs :: Params (m v) + -> (forall a. m v -> (AttrSet (m v) -> m v -> m (a, v)) -> m (a, v)) + -> m v {- - evalSelect :: v -> NonEmpty Text -> Maybe (m v) -> m v - evalHasAttr :: v -> NonEmpty Text -> m v + evalSelect :: v -> NonEmpty Text -> Maybe (m v) -> m v + evalHasAttr :: v -> NonEmpty Text -> m v - -- | This and the following methods are intended to allow things like - -- adding provenance information. - evalListElem :: [m v] -> Int -> m v -> m v - evalList :: [t] -> m v - evalSetElem :: AttrSet (m v) -> Text -> m v -> m v - evalSet :: AttrSet t -> AttrSet SourcePos -> m v - evalRecSetElem :: AttrSet (m v) -> Text -> m v -> m v - evalRecSet :: AttrSet t -> AttrSet SourcePos -> m v - evalLetElem :: Text -> m v -> m v - evalLet :: m v -> m v + -- | This and the following methods are intended to allow things like + -- adding provenance information. + evalListElem :: [m v] -> Int -> m v -> m v + evalList :: [v] -> m v + evalSetElem :: AttrSet (m v) -> Text -> m v -> m v + evalSet :: AttrSet v -> AttrSet SourcePos -> m v + evalRecSetElem :: AttrSet (m v) -> Text -> m v -> m v + evalRecSet :: AttrSet v -> AttrSet SourcePos -> m v + evalLetElem :: Text -> m v -> m v + evalLet :: m v -> m v -} - evalError :: Exception s => s -> m a + evalError :: Exception s => s -> m a -type MonadNixEval v t m +type MonadNixEval v m = ( MonadEval v m - , Scoped t m - , MonadThunk t m v + , Scoped v m + , MonadValue v m , MonadFix m , ToValue Bool m v - , ToValue [t] m v + , ToValue [v] m v , FromValue NixString m v - , ToValue (AttrSet t, AttrSet SourcePos) m v - , FromValue (AttrSet t, AttrSet SourcePos) m v + , ToValue (AttrSet v, AttrSet SourcePos) m v + , FromValue (AttrSet v, AttrSet SourcePos) m v ) -data EvalFrame m t - = EvaluatingExpr (Scopes m t) NExprLoc - | ForcingExpr (Scopes m t) NExprLoc +data EvalFrame m v + = EvaluatingExpr (Scopes m v) NExprLoc + | ForcingExpr (Scopes m v) NExprLoc | Calling String SrcSpan - | SynHole (SynHoleInfo m t) + | SynHole (SynHoleInfo m v) deriving (Show, Typeable) -instance (Typeable m, Typeable t) => Exception (EvalFrame m t) +instance (Typeable m, Typeable v) => Exception (EvalFrame m v) -data SynHoleInfo m t = SynHoleInfo +data SynHoleInfo m v = SynHoleInfo { _synHoleInfo_expr :: NExprLoc - , _synHoleInfo_scope :: Scopes m t + , _synHoleInfo_scope :: Scopes m v } deriving (Show, Typeable) -instance (Typeable m, Typeable t) => Exception (SynHoleInfo m t) +instance (Typeable m, Typeable v) => Exception (SynHoleInfo m v) -eval :: forall v t m . MonadNixEval v t m => NExprF (m v) -> m v +-- jww (2019-03-18): By deferring only those things which must wait until +-- context of us, this can be written as: +-- eval :: forall v m . MonadNixEval v m => NExprF v -> m v +eval :: forall v m . MonadNixEval v m => NExprF (m v) -> m v eval (NSym "__curPos") = evalCurPos -eval (NSym var ) = (lookupVar var :: m (Maybe t)) - >>= maybe (freeVariable var) (force ?? evaledSym var) +eval (NSym var ) = (lookupVar var :: m (Maybe v)) + >>= maybe (freeVariable var) (demand ?? evaledSym var) eval (NConstant x ) = evalConstant x eval (NStr str ) = evalString str @@ -121,7 +129,7 @@ eval (NEnvPath p ) = evalEnvPath p eval (NUnary op arg ) = evalUnary op =<< arg eval (NBinary NApp fun arg) = do - scope <- currentScopes :: m (Scopes m t) + scope <- currentScopes :: m (Scopes m v) fun >>= (`evalApp` withScopes scope arg) eval (NBinary op larg rarg) = larg >>= evalBinary op ?? rarg @@ -133,7 +141,7 @@ eval (NHasAttr aset attr) = evalSelect aset attr >>= toValue . isRight eval (NList l ) = do scope <- currentScopes - for l (thunk @t @m @v . withScopes @t scope) >>= toValue + for l (defer @v @m . withScopes @v scope) >>= toValue eval (NSet binds) = evalBinds False (desugarBinds (eval . NSet) binds) >>= toValue @@ -154,32 +162,32 @@ eval (NAbs params body) = do -- needs to be used when evaluating the body and default arguments, hence -- we defer here so the present scope is restored when the parameters and -- body are forced during application. - scope <- currentScopes :: m (Scopes m t) + scope <- currentScopes :: m (Scopes m v) evalAbs params $ \arg k -> withScopes scope $ do args <- buildArgument params arg - pushScope args (k (M.map (`force` pure) args) body) + pushScope args (k (M.map (`demand` pure) args) body) eval (NSynHole name) = synHole name --- | If you know that the 'scope' action will result in an 'AttrSet t', then +-- | If you know that the 'scope' action will result in an 'AttrSet v', then -- this implementation may be used as an implementation for 'evalWith'. -evalWithAttrSet :: forall v t m . MonadNixEval v t m => m v -> m v -> m v +evalWithAttrSet :: forall v m . MonadNixEval v m => m v -> m v -> m v evalWithAttrSet aset body = do -- The scope is deliberately wrapped in a thunk here, since it is -- evaluated each time a name is looked up within the weak scope, and -- we want to be sure the action it evaluates is to force a thunk, so -- its value is only computed once. - scope <- currentScopes :: m (Scopes m t) - s <- thunk @t @m @v $ withScopes scope aset + scope <- currentScopes :: m (Scopes m v) + s <- defer @v @m $ withScopes scope aset pushWeakScope ?? body - $ force s + $ demand s $ fmap fst - . fromValue @(AttrSet t, AttrSet SourcePos) + . fromValue @(AttrSet v, AttrSet SourcePos) attrSetAlter - :: forall v t m - . MonadNixEval v t m + :: forall v m + . MonadNixEval v m => [Text] -> SourcePos -> AttrSet (m v) @@ -196,17 +204,16 @@ attrSetAlter (k : ks) pos m p val = case M.lookup k m of | null ks -> go | otherwise - -> x >>= fromValue @(AttrSet t, AttrSet SourcePos) >>= \(st, sp) -> - recurse (force ?? pure <$> st) sp + -> x >>= fromValue @(AttrSet v, AttrSet SourcePos) >>= \(st, sp) -> + recurse (demand ?? pure <$> st) sp where go = return (M.insert k val m, M.insert k pos p) recurse st sp = attrSetAlter ks pos st sp val <&> \(st', _) -> ( M.insert k - ( toValue @(AttrSet t, AttrSet SourcePos) + ( toValue @(AttrSet v, AttrSet SourcePos) =<< (, mempty) - . fmap wrapValue <$> sequence st' ) st @@ -240,13 +247,13 @@ desugarBinds embed binds = evalState (mapM (go <=< collect) binds) M.empty Just (p, v) -> pure $ NamedVar (StaticKey x :| []) (embed v) p evalBinds - :: forall v t m - . MonadNixEval v t m + :: forall v m + . MonadNixEval v m => Bool -> [Binding (m v)] - -> m (AttrSet t, AttrSet SourcePos) + -> m (AttrSet v, AttrSet SourcePos) evalBinds recursive binds = do - scope <- currentScopes :: m (Scopes m t) + scope <- currentScopes :: m (Scopes m v) buildResult scope . concat =<< mapM (go scope) (moveOverridesLast binds) where moveOverridesLast = uncurry (++) . partition @@ -255,12 +262,12 @@ evalBinds recursive binds = do _ -> True ) - go :: Scopes m t -> Binding (m v) -> m [([Text], SourcePos, m v)] + go :: Scopes m v -> Binding (m v) -> m [([Text], SourcePos, m v)] go _ (NamedVar (StaticKey "__overrides" :| []) finalValue pos) = finalValue >>= fromValue >>= \(o', p') -> -- jww (2018-05-09): What to do with the key position here? return $ map - (\(k, v) -> ([k], fromMaybe pos (M.lookup k p'), force @t @m @v v pure)) + (\(k, v) -> ([k], fromMaybe pos (M.lookup k p'), demand @v @m v pure)) (M.toList o') go _ (NamedVar pathExpr finalValue pos) = do @@ -271,7 +278,7 @@ evalBinds recursive binds = do pure ( [] , nullPos - , toValue @(AttrSet t, AttrSet SourcePos) (mempty, mempty) + , toValue @(AttrSet v, AttrSet SourcePos) (mempty, mempty) ) Just k -> case t of [] -> pure ([k], pos, finalValue) @@ -294,31 +301,31 @@ evalBinds recursive binds = do mv <- case ms of Nothing -> withScopes scope $ lookupVar key Just s -> - s >>= fromValue @(AttrSet t, AttrSet SourcePos) >>= \(s, _) -> - clearScopes @t $ pushScope s $ lookupVar key + s >>= fromValue @(AttrSet v, AttrSet SourcePos) >>= \(s, _) -> + clearScopes @v $ pushScope s $ lookupVar key case mv of Nothing -> attrMissing (key :| []) Nothing - Just v -> force v pure + Just v -> demand v pure ) buildResult - :: Scopes m t + :: Scopes m v -> [([Text], SourcePos, m v)] - -> m (AttrSet t, AttrSet SourcePos) + -> m (AttrSet v, AttrSet SourcePos) buildResult scope bindings = do (s, p) <- foldM insert (M.empty, M.empty) bindings res <- if recursive then loebM (encapsulate <$> s) else traverse mkThunk s return (res, p) where - mkThunk = thunk . withScopes scope + mkThunk = defer . withScopes scope encapsulate f attrs = mkThunk . pushScope attrs $ f insert (m, p) (path, pos, value) = attrSetAlter path pos m p value evalSelect - :: forall v t m - . MonadNixEval v t m + :: forall v m + . MonadNixEval v m => m v -> NAttrPath (m v) -> m (Either (v, NonEmpty Text) (m v)) @@ -328,10 +335,10 @@ evalSelect aset attr = do extract s path where extract x path@(k :| ks) = fromValueMay x >>= \case - Just (s :: AttrSet t, p :: AttrSet SourcePos) + Just (s :: AttrSet v, p :: AttrSet SourcePos) | Just t <- M.lookup k s -> case ks of - [] -> pure $ Right $ force t pure - y : ys -> force t $ extract ?? (y :| ys) + [] -> pure $ Right $ demand t pure + y : ys -> demand t $ extract ?? (y :| ys) | otherwise -> Left . (, path) <$> toValue (s, p) Nothing -> return $ Left (x, path) @@ -376,16 +383,16 @@ assembleString = \case (>>= fromValueMay) buildArgument - :: forall v t m . MonadNixEval v t m => Params (m v) -> m v -> m (AttrSet t) + :: forall v m . MonadNixEval v m => Params (m v) -> m v -> m (AttrSet v) buildArgument params arg = do - scope <- currentScopes :: m (Scopes m t) + scope <- currentScopes :: m (Scopes m v) case params of - Param name -> M.singleton name <$> thunk (withScopes scope arg) + Param name -> M.singleton name <$> defer (withScopes scope arg) ParamSet s isVariadic m -> - arg >>= fromValue @(AttrSet t, AttrSet SourcePos) >>= \(args, _) -> do + arg >>= fromValue @(AttrSet v, AttrSet SourcePos) >>= \(args, _) -> do let inject = case m of Nothing -> id - Just n -> M.insert n $ const $ thunk (withScopes scope arg) + Just n -> M.insert n $ const $ defer (withScopes scope arg) loebM (inject $ M.mapMaybe id $ alignWithKey (assemble scope isVariadic) args @@ -393,11 +400,11 @@ buildArgument params arg = do ) where assemble - :: Scopes m t + :: Scopes m v -> Bool -> Text - -> These t (Maybe (m v)) - -> Maybe (AttrSet t -> m t) + -> These v (Maybe (m v)) + -> Maybe (AttrSet v -> m v) assemble scope isVariadic k = \case That Nothing -> Just @@ -407,7 +414,7 @@ buildArgument params arg = do $ "Missing value for parameter: " ++ show k That (Just f) -> - Just $ \args -> thunk $ withScopes scope $ pushScope args f + Just $ \args -> defer $ withScopes scope $ pushScope args f This _ | isVariadic -> Nothing @@ -426,17 +433,17 @@ addSourcePositions f v@(Fix (Compose (Ann ann _))) = local (set hasLens ann) (f v) addStackFrames - :: forall t e m a - . (Scoped t m, Framed e m, Typeable t, Typeable m) + :: forall v e m a + . (Scoped v m, Framed e m, Typeable v, Typeable m) => Transform NExprLocF (m a) addStackFrames f v = do - scopes <- currentScopes :: m (Scopes m t) + scopes <- currentScopes :: m (Scopes m v) withFrame Info (EvaluatingExpr scopes v) (f v) framedEvalExprLoc - :: forall t e v m - . (MonadNixEval v t m, Framed e m, Has e SrcSpan, Typeable t, Typeable m) + :: forall e v m + . (MonadNixEval v m, Framed e m, Has e SrcSpan, Typeable m, Typeable v) => NExprLoc -> m v framedEvalExprLoc = - adi (eval . annotated . getCompose) (addStackFrames @t . addSourcePositions) + adi (eval . annotated . getCompose) (addStackFrames @v . addSourcePositions) diff --git a/src/Nix/Exec.hs b/src/Nix/Exec.hs index dc608b1..fc80a1b 100644 --- a/src/Nix/Exec.hs +++ b/src/Nix/Exec.hs @@ -35,6 +35,7 @@ import Control.Applicative import Control.Monad import Control.Monad.Catch hiding ( catchJust ) import Control.Monad.Fix +import Control.Monad.Free import Control.Monad.Reader import Control.Monad.Ref import Control.Monad.State.Strict @@ -71,6 +72,7 @@ import Nix.Thunk import Nix.Utils import Nix.Value import Nix.Value.Equal +import Nix.Value.Monad #ifdef MIN_VERSION_haskeline import System.Console.Haskeline.MonadException hiding(catch) #endif @@ -86,64 +88,69 @@ import GHC.DataSize #endif type MonadCited t f m - = (HasCitations1 t m (NValue t f m) f, MonadDataContext f m) + = ( HasCitations m (NValue t f m) t + , HasCitations1 m (NValue t f m) f + , MonadDataContext f m + ) nvConstantP - :: MonadCited t f m => Provenance t m (NValue t f m) -> NAtom -> NValue t f m + :: MonadCited t f m => Provenance m (NValue t f m) -> NAtom -> NValue t f m nvConstantP p x = addProvenance p (nvConstant x) nvStrP :: MonadCited t f m - => Provenance t m (NValue t f m) + => Provenance m (NValue t f m) -> NixString -> NValue t f m nvStrP p ns = addProvenance p (nvStr ns) nvPathP :: MonadCited t f m - => Provenance t m (NValue t f m) + => Provenance m (NValue t f m) -> FilePath -> NValue t f m nvPathP p x = addProvenance p (nvPath x) -nvListP - :: MonadCited t f m => Provenance t m (NValue t f m) -> [t] -> NValue t f m +nvListP :: MonadCited t f m + => Provenance m (NValue t f m) -> [NValue t f m] -> NValue t f m nvListP p l = addProvenance p (nvList l) nvSetP :: MonadCited t f m - => Provenance t m (NValue t f m) - -> AttrSet t + => Provenance m (NValue t f m) + -> AttrSet (NValue t f m) -> AttrSet SourcePos -> NValue t f m nvSetP p s x = addProvenance p (nvSet s x) nvClosureP :: MonadCited t f m - => Provenance t m (NValue t f m) + => Provenance m (NValue t f m) -> Params () - -> (m (NValue t f m) -> m t) + -> (NValue t f m -> m (NValue t f m)) -> NValue t f m nvClosureP p x f = addProvenance p (nvClosure x f) nvBuiltinP :: MonadCited t f m - => Provenance t m (NValue t f m) + => Provenance m (NValue t f m) -> String - -> (m (NValue t f m) -> m t) + -> (NValue t f m -> m (NValue t f m)) -> NValue t f m nvBuiltinP p name f = addProvenance p (nvBuiltin name f) type MonadCitedThunks t f m - = ( MonadThunk t m (NValue t f m) + = ( MonadValue (NValue t f m) m + , MonadThunk t m (NValue t f m) , MonadDataErrorContext t f m - , HasCitations1 t m (NValue t f m) f + , HasCitations m (NValue t f m) t + , HasCitations1 m (NValue t f m) f ) type MonadNix e t f m = ( Has e SrcSpan , Has e Options - , Scoped t m + , Scoped (NValue t f m) m , Framed e m , MonadFix m , MonadCatch m @@ -151,6 +158,7 @@ type MonadNix e t f m , Alternative m , MonadEffects t f m , MonadCitedThunks t f m + , MonadValue (NValue t f m) m ) data ExecFrame t f m = Assertion SrcSpan (NValue t f m) @@ -288,7 +296,7 @@ instance MonadNix e t f m => MonadEval (NValue t f m) m where scope <- currentScopes span <- currentPos addProvenance (Provenance scope (NBinary_ span NApp (Just f) Nothing)) - <$> callFunc f x + <$> (callFunc f =<< defer x) evalAbs p k = do scope <- currentScopes @@ -296,7 +304,7 @@ instance MonadNix e t f m => MonadEval (NValue t f m) m where pure $ nvClosureP (Provenance scope (NAbs_ span (Nothing <$ p) Nothing)) (void p) - (\arg -> wrapValue . snd <$> k arg (\_ b -> ((), ) <$> b)) + (\arg -> snd <$> k (pure arg) (\_ b -> ((), ) <$> b)) evalError = throwError @@ -305,27 +313,27 @@ callFunc :: forall e t f m . MonadNix e t f m => NValue t f m + -> NValue t f m -> m (NValue t f m) - -> m (NValue t f m) -callFunc fun arg = do +callFunc fun arg = demand fun $ \fun' -> do frames :: Frames <- asks (view hasLens) when (length frames > 2000) $ throwError $ ErrorCall "Function call stack exhausted" - case fun of + case fun' of NVClosure params f -> do traceM $ "callFunc:NVFunction taking " ++ show params - force ?? pure =<< f arg + f arg NVBuiltin name f -> do span <- currentPos - force ?? pure =<< withFrame Info (Calling @m @t name span) (f arg) + withFrame Info (Calling @m @t name span) (f arg) s@(NVSet m _) | Just f <- M.lookup "__functor" m -> do traceM "callFunc:__functor" - force f $ (`callFunc` pure s) >=> (`callFunc` arg) + demand f $ (`callFunc` s) >=> (`callFunc` arg) x -> throwError $ ErrorCall $ "Attempt to call non-function: " ++ show x execUnaryOp :: (Framed e m, MonadCited t f m, Show t) - => Scopes m t + => Scopes m (NValue t f m) -> SrcSpan -> NUnaryOp -> NValue t f m @@ -354,23 +362,23 @@ execUnaryOp scope span op arg = do execBinaryOp :: forall e t f m . (MonadNix e t f m, MonadEval (NValue t f m) m) - => Scopes m t + => Scopes m (NValue t f m) -> SrcSpan -> NBinaryOp -> NValue t f m -> m (NValue t f m) -> m (NValue t f m) -execBinaryOp scope span NOr larg rarg = fromNix larg >>= \l -> if l +execBinaryOp scope span NOr larg rarg = fromValue larg >>= \l -> if l then orOp Nothing True - else rarg >>= \rval -> fromNix @Bool rval >>= orOp (Just rval) + else rarg >>= \rval -> fromValue @Bool rval >>= orOp (Just rval) where orOp r b = pure $ nvConstantP (Provenance scope (NBinary_ span NOr (Just larg) r)) (NBool b) -execBinaryOp scope span NAnd larg rarg = fromNix larg >>= \l -> if l - then rarg >>= \rval -> fromNix @Bool rval >>= andOp (Just rval) +execBinaryOp scope span NAnd larg rarg = fromValue larg >>= \l -> if l + then rarg >>= \rval -> fromValue @Bool rval >>= andOp (Just rval) else andOp Nothing False where andOp r b = pure $ nvConstantP @@ -379,7 +387,7 @@ execBinaryOp scope span NAnd larg rarg = fromNix larg >>= \l -> if l execBinaryOp scope span op lval rarg = do rval <- rarg - let bin :: (Provenance t m (NValue t f m) -> a) -> a + let bin :: (Provenance m (NValue t f m) -> a) -> a bin f = f (Provenance scope (NBinary_ span op (Just lval) (Just rval))) toBool = pure . bin nvConstantP . NBool case (lval, rval) of @@ -499,7 +507,7 @@ execBinaryOp scope span op lval rarg = do ++ show rval numBinOp - :: (forall r . (Provenance t m (NValue t f m) -> r) -> r) + :: (forall r . (Provenance m (NValue t f m) -> r) -> r) -> (forall a . Num a => a -> a -> a) -> NAtom -> NAtom @@ -507,7 +515,7 @@ execBinaryOp scope span op lval rarg = do numBinOp bin f = numBinOp' bin f f numBinOp' - :: (forall r . (Provenance t m (NValue t f m) -> r) -> r) + :: (forall r . (Provenance m (NValue t f m) -> r) -> r) -> (Integer -> Integer -> Integer) -> (Float -> Float -> Float) -> NAtom @@ -565,12 +573,12 @@ coerceToString ctsm clevel = go | ctsm == CopyToStore -> storePathToNixString <$> addPath p | otherwise -> pure $ principledMakeNixStringWithoutContext $ Text.pack p NVList l | clevel == CoerceAny -> - nixStringUnwords <$> traverse (`force` go) l + nixStringUnwords <$> traverse (`demand` go) l v@(NVSet s _) | Just p <- M.lookup "__toString" s -> - force p $ (`callFunc` pure v) >=> go + demand p $ (`callFunc` v) >=> go - NVSet s _ | Just p <- M.lookup "outPath" s -> force p go + NVSet s _ | Just p <- M.lookup "outPath" s -> demand p go v -> throwError $ ErrorCall $ "Expected a string, but saw: " ++ show v @@ -588,7 +596,7 @@ fromStringNoContext ns = case principledGetStringNoContext ns of Nothing -> throwError $ ErrorCall "expected string with no context" newtype Lazy t (f :: * -> *) m a = Lazy - { runLazy :: ReaderT (Context (Lazy t f m) t) + { runLazy :: ReaderT (Context (Lazy t f m) (NValue t f (Lazy t f m))) (StateT (HashMap FilePath NExprLoc) m) a } deriving ( Functor @@ -600,7 +608,7 @@ newtype Lazy t (f :: * -> *) m a = Lazy , MonadIO , MonadCatch , MonadThrow - , MonadReader (Context (Lazy t f m) t) + , MonadReader (Context (Lazy t f m) (NValue t f (Lazy t f m))) ) instance MonadTrans (Lazy t f) where @@ -662,7 +670,7 @@ instance ( MonadFix m mres <- lookupVar "__cur_file" case mres of Nothing -> getCurrentDirectory - Just v -> force v $ \case + Just v -> demand v $ \case NVPath s -> return $ takeDirectory s v -> throwError @@ -699,17 +707,18 @@ instance ( MonadFix m Lazy $ ReaderT $ const $ modify (M.insert path expr) pure expr - derivationStrict = fromValue @(AttrSet t) >=> \s -> do - nn <- maybe (pure False) (force ?? fromNix) (M.lookup "__ignoreNulls" s) + derivationStrict = fromValue @(AttrSet (NValue t f (Lazy t f m))) >=> \s -> do + nn <- maybe (pure False) (force ?? fromValue) (M.lookup "__ignoreNulls" s) s' <- M.fromList <$> mapMaybeM (handleEntry nn) (M.toList s) - v' <- normalForm =<< toValue @(AttrSet t) @_ @(NValue t f (Lazy t f m)) s' + v' <- normalForm =<< toValue @(AttrSet (NValue t f (Lazy t f m))) @_ @(NValue t f (Lazy t f m)) s' nixInstantiateExpr $ "derivationStrict " ++ show (prettyNValueNF v') where mapMaybeM :: (a -> Lazy t f m (Maybe b)) -> [a] -> Lazy t f m [b] mapMaybeM op = foldr f (return []) where f x xs = op x >>= (<$> xs) . (++) . maybeToList - handleEntry :: Bool -> (Text, t) -> Lazy t f m (Maybe (Text, t)) + handleEntry :: Bool -> (Text, NValue t f (Lazy t f m)) + -> Lazy t f m (Maybe (Text, NValue t f (Lazy t f m))) handleEntry ignoreNulls (k, v) = fmap (k, ) <$> case k of -- The `args' attribute is special: it supplies the command-line -- arguments to the builder. @@ -721,16 +730,15 @@ instance ( MonadFix m NVConstant NNull | ignoreNulls -> pure Nothing v' -> Just <$> coerceNix v' where - coerceNix :: NValue t f (Lazy t f m) -> Lazy t f m t - coerceNix = - fmap wrapValue . toNix <=< coerceToString CopyToStore CoerceAny + coerceNix :: NValue t f (Lazy t f m) -> Lazy t f m (NValue t f (Lazy t f m)) + coerceNix = toValue <=< coerceToString CopyToStore CoerceAny - coerceNixList :: NValue t f (Lazy t f m) -> Lazy t f m t + coerceNixList :: NValue t f (Lazy t f m) -> Lazy t f m (NValue t f (Lazy t f m)) coerceNixList v = do - xs :: [t] <- fromValue @[t] v - ys :: [t] <- traverse (\x -> force x coerceNix) xs - v' :: NValue t f (Lazy t f m) <- toValue @[t] ys - return $ wrapValue v' + xs :: [NValue t f (Lazy t f m)] <- fromValue @[NValue t f (Lazy t f m)] v + ys :: [NValue t f (Lazy t f m)] <- traverse (\x -> demand x coerceNix) xs + v' :: NValue t f (Lazy t f m) <- toValue @[NValue t f (Lazy t f m)] ys + return v' traceEffect = putStrLn @@ -775,7 +783,7 @@ findPathBy :: forall e t f m . MonadNix e t f m => (FilePath -> m (Maybe FilePath)) - -> [t] + -> [NValue t f m] -> FilePath -> m FilePath findPathBy finder l name = do @@ -790,13 +798,13 @@ findPathBy finder l name = do ++ " (add it using $NIX_PATH or -I)" Just path -> return path where - go :: Maybe FilePath -> t -> m (Maybe FilePath) + go :: Maybe FilePath -> NValue t f m -> m (Maybe FilePath) go p@(Just _) _ = pure p - go Nothing l = force l $ fromValue >=> \(s :: HashMap Text t) -> do + go Nothing l = demand l $ fromValue >=> \(s :: HashMap Text (NValue t f m)) -> do p <- resolvePath s - force p $ fromValue >=> \(Path path) -> case M.lookup "prefix" s of + demand p $ fromValue >=> \(Path path) -> case M.lookup "prefix" s of Nothing -> tryPath path Nothing - Just pf -> force pf $ fromValueMay >=> \case + Just pf -> demand pf $ fromValueMay >=> \case Just (nsPfx :: NixString) -> let pfx = hackyStringIgnoreContext nsPfx in if not (Text.null pfx) @@ -811,7 +819,7 @@ findPathBy finder l name = do resolvePath s = case M.lookup "path" s of Just t -> return t Nothing -> case M.lookup "uri" s of - Just ut -> thunk $ fetchTarball (force ut pure) + Just ut -> defer $ fetchTarball (demand ut pure) Nothing -> throwError $ ErrorCall @@ -819,7 +827,8 @@ findPathBy finder l name = do ++ " with 'path' elements, but saw: " ++ show s -findPathM :: forall e t f m . MonadNix e t f m => [t] -> FilePath -> m FilePath +findPathM :: forall e t f m . MonadNix e t f m + => [NValue t f m] -> FilePath -> m FilePath findPathM l name = findPathBy path l name where path :: MonadEffects t f m => FilePath -> m (Maybe FilePath) @@ -833,8 +842,8 @@ findEnvPathM name = do mres <- lookupVar "__nixPath" case mres of Nothing -> error "impossible" - Just x -> - force x $ fromValue >=> \(l :: [t]) -> findPathBy nixFilePath l name + Just x -> demand x $ fromValue >=> \(l :: [NValue t f m]) -> + findPathBy nixFilePath l name where nixFilePath :: MonadEffects t f m => FilePath -> m (Maybe FilePath) nixFilePath path = do @@ -877,9 +886,9 @@ evalExprLoc expr = do if tracing opts then join . (`runReaderT` (0 :: Int)) $ adi (addTracing phi) - (raise (addStackFrames @t . addSourcePositions)) + (raise (addStackFrames @(NValue t f m) . addSourcePositions)) expr - else adi phi (addStackFrames @t . addSourcePositions) expr + else adi phi (addStackFrames @(NValue t f m) . addSourcePositions) expr where phi = Eval.eval . annotated . getCompose raise k f x = ReaderT $ \e -> k (\t -> runReaderT (f t) e) x @@ -890,7 +899,7 @@ fetchTarball v = v >>= \case NVSet s _ -> case M.lookup "url" s of Nothing -> throwError $ ErrorCall "builtins.fetchTarball: Missing url attribute" - Just url -> force url $ go (M.lookup "sha256" s) + Just url -> demand url $ go (M.lookup "sha256" s) v@NVStr{} -> go Nothing v v -> throwError @@ -898,7 +907,7 @@ fetchTarball v = v >>= \case $ "builtins.fetchTarball: Expected URI or set, got " ++ show v where - go :: Maybe t -> NValue t f m -> m (NValue t f m) + go :: Maybe (NValue t f m) -> NValue t f m -> m (NValue t f m) go msha = \case NVStr ns -> fetch (hackyStringIgnoreContext ns) msha v -> @@ -919,10 +928,10 @@ fetchTarball v = v >>= \case ++ ext ++ "'" -} - fetch :: Text -> Maybe t -> m (NValue t f m) + fetch :: Text -> Maybe (NValue t f m) -> m (NValue t f m) fetch uri Nothing = nixInstantiateExpr $ "builtins.fetchTarball \"" ++ Text.unpack uri ++ "\"" - fetch url (Just t) = force t $ fromValue >=> \nsSha -> + fetch url (Just t) = demand t $ fromValue >=> \nsSha -> let sha = hackyStringIgnoreContext nsSha in nixInstantiateExpr $ "builtins.fetchTarball { " @@ -940,15 +949,8 @@ nixInstantiateExpr :: (MonadNix e t f m, MonadInstantiate m) => String -> m (NValue t f m) nixInstantiateExpr s = either throwError evalExprLoc =<< instantiateExpr s -instance Monad m => Scoped t (Lazy t f m) where +instance Monad m => Scoped (NValue t f (Lazy t f m)) (Lazy t f m) where currentScopes = currentScopesReader - clearScopes = clearScopesReader @(Lazy t f m) @t + clearScopes = clearScopesReader @(Lazy t f m) @(NValue t f (Lazy t f m)) pushScopes = pushScopesReader lookupVar = lookupVarReader - - - - - - - diff --git a/src/Nix/Normal.hs b/src/Nix/Normal.hs index 489bc3a..a34cfbb 100644 --- a/src/Nix/Normal.hs +++ b/src/Nix/Normal.hs @@ -13,21 +13,26 @@ module Nix.Normal where import Control.Monad +import Control.Monad.Free import Control.Monad.Trans.Class import Control.Monad.Trans.Reader import Control.Monad.Trans.State +import Data.Fix import Data.Set +import Nix.Cited import Nix.Frames import Nix.String import Nix.Thunk import Nix.Value +import Nix.Utils newtype NormalLoop t f m = NormalLoop (NValue t f m) deriving Show instance MonadDataErrorContext t f m => Exception (NormalLoop t f m) -normalForm' +-- | Normalize the value as much as possible, leaving only detected cycles. +normalize :: forall e t m f . ( Framed e m , MonadThunk t m (NValue t f m) @@ -36,8 +41,8 @@ normalForm' ) => (forall r . t -> (NValue t f m -> m r) -> m r) -> NValue t f m - -> m (NValueNF t f m) -normalForm' f = run . nValueToNFM run go + -> m (NValue t f m) +normalize f = run . iterNValueM run go (fmap Free . sequenceNValue' run) where start = 0 :: Int table = mempty @@ -48,39 +53,54 @@ normalForm' f = run . nValueToNFM run go go :: t -> ( NValue t f m - -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValueNF t f m) + -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m) ) - -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValueNF t f m) + -> ReaderT Int (StateT (Set (ThunkId m)) m) (NValue t f m) go t k = do b <- seen t if b - then return $ pure t + then return $ Pure t else do i <- ask when (i > 2000) $ error "Exceeded maximum normalization depth of 2000 levels" - s <- lift get - (res, s') <- lift $ lift $ f t $ \v -> - (`runStateT` s) . (`runReaderT` i) $ local succ $ k v - lift $ put s' - return res + lifted (lifted (f t)) $ local succ . k - seen t = case thunkId t of - Just tid -> lift $ do + seen t = do + let tid = thunkId t + lift $ do res <- gets (member tid) unless res $ modify (insert tid) return res - Nothing -> return False + +stubCycles + :: forall t f m + . ( Applicative f + , Functor m + , HasCitations m (NValue t f m) t + , HasCitations1 m (NValue t f m) f + ) + => NValue t f m -> NValueNF t f m +stubCycles = freeToFix $ \t -> Fix + $ NValue + $ Prelude.foldr (addProvenance1 @m @(NValue t f m)) cyc + $ reverse + $ citations @m @(NValue t f m) t + where + Fix (NValue cyc) = + nvStrNF (principledMakeNixStringWithoutContext "") normalForm :: ( Framed e m , MonadThunk t m (NValue t f m) , MonadDataErrorContext t f m + , HasCitations m (NValue t f m) t + , HasCitations1 m (NValue t f m) f , Ord (ThunkId m) ) => NValue t f m -> m (NValueNF t f m) -normalForm = normalForm' force +normalForm = fmap stubCycles . normalize force normalForm_ :: ( Framed e m @@ -90,19 +110,13 @@ normalForm_ ) => NValue t f m -> m () -normalForm_ = void <$> normalForm' forceEff +normalForm_ = void <$> normalize forceEff removeEffects - :: (MonadThunk t m (NValue t f m), MonadDataContext f m) - => NValue t f m - -> NValueNF t f m -removeEffects = nValueToNF (flip query opaque) - -removeEffectsM :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => NValue t f m -> m (NValueNF t f m) -removeEffectsM = nValueToNFM id (flip queryM (pure opaque)) +removeEffects = nValueToNFM id (flip queryM (pure opaque)) opaque :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => NValueNF t f m @@ -112,4 +126,4 @@ dethunk :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => t -> m (NValueNF t f m) -dethunk t = queryM t (pure opaque) removeEffectsM +dethunk t = queryM t (pure opaque) removeEffects diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index 45c1492..9f96ddd 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -18,6 +18,7 @@ module Nix.Pretty where import Control.Applicative ( (<|>) ) import Control.Comonad +import Control.Monad.Free import Data.Fix import Data.HashMap.Lazy ( toList ) import qualified Data.HashMap.Lazy as M @@ -192,14 +193,25 @@ prettyAtom atom = simpleExpr $ pretty $ unpack $ atomText atom prettyNix :: NExpr -> Doc ann prettyNix = withoutParens . cata exprFNixDoc -instance HasCitations1 t m v f - => HasCitations t m v (NValue' t f m a) where +instance HasCitations1 m v f + => HasCitations m v (NValue' t f m a) where citations (NValue f) = citations1 f addProvenance x (NValue f) = NValue (addProvenance1 x f) +instance (HasCitations1 m v f, HasCitations m v t) + => HasCitations m v (NValue t f m) where + citations (Pure t) = citations t + citations (Free v) = citations v + addProvenance x (Pure t) = Pure (addProvenance x t) + addProvenance x (Free v) = Free (addProvenance x v) + +instance HasCitations1 m v f => HasCitations m v (NValueNF t f m) where + citations (Fix v) = citations v + addProvenance x (Fix v) = Fix (addProvenance x v) + prettyOriginExpr :: forall t f m ann - . HasCitations1 t m (NValue t f m) f + . HasCitations1 m (NValue t f m) f => NExprLocF (Maybe (NValue t f m)) -> Doc ann prettyOriginExpr = withoutParens . go @@ -208,7 +220,7 @@ prettyOriginExpr = withoutParens . go render :: Maybe (NValue t f m) -> NixDoc ann render Nothing = simpleExpr $ "_" - render (Just (reverse . citations @t @m -> p:_)) = go (_originExpr p) + render (Just (Free (reverse . citations @m -> p:_))) = go (_originExpr p) render _ = simpleExpr "?" -- render (Just (NValue (citations -> ps))) = -- simpleExpr $ foldr ((\x y -> vsep [x, y]) . parens . indent 2 . withoutParens @@ -314,21 +326,19 @@ exprFNixDoc = \case where recPrefix = "rec" <> space valueToExpr :: forall t f m . MonadDataContext f m => NValueNF t f m -> NExpr -valueToExpr = iterNValueNF - (const (mkStr (principledMakeNixStringWithoutContext ""))) - phi +valueToExpr = iterNValueNF phi where phi :: NValue' t f m NExpr -> NExpr - phi (NVConstant a ) = Fix $ NConstant a - phi (NVStr ns) = mkStr ns - phi (NVList l ) = Fix $ NList l - phi (NVSet s p ) = Fix $ NSet + phi (NVConstant' a ) = Fix $ NConstant a + phi (NVStr' ns) = mkStr ns + phi (NVList' l ) = Fix $ NList l + phi (NVSet' s p ) = Fix $ NSet [ NamedVar (StaticKey k :| []) v (fromMaybe nullPos (M.lookup k p)) | (k, v) <- toList s ] - phi (NVClosure _ _ ) = Fix . NSym . pack $ "" - phi (NVPath p ) = Fix $ NLiteralPath p - phi (NVBuiltin name _) = Fix . NSym . pack $ "builtins." ++ name + phi (NVClosure' _ _ ) = Fix . NSym . pack $ "" + phi (NVPath' p ) = Fix $ NLiteralPath p + phi (NVBuiltin' name _) = Fix . NSym . pack $ "builtins." ++ name phi _ = error "Pattern synonyms foil completeness check" mkStr ns = Fix $ NStr $ DoubleQuoted [Plain (hackyStringIgnoreContext ns)] @@ -337,13 +347,13 @@ prettyNValueNF :: MonadDataContext f m => NValueNF t f m -> Doc ann prettyNValueNF = prettyNix . valueToExpr printNix :: forall t f m . MonadDataContext f m => NValueNF t f m -> String -printNix = iterNValueNF (const "") phi +printNix = iterNValueNF phi where phi :: NValue' t f m String -> String - phi (NVConstant a ) = unpack $ atomText a - phi (NVStr ns) = show $ hackyStringIgnoreContext ns - phi (NVList l ) = "[ " ++ unwords l ++ " ]" - phi (NVSet s _) = + phi (NVConstant' a ) = unpack $ atomText a + phi (NVStr' ns) = show $ hackyStringIgnoreContext ns + phi (NVList' l ) = "[ " ++ unwords l ++ " ]" + phi (NVSet' s _) = "{ " ++ concat [ check (unpack k) ++ " = " ++ v ++ "; " @@ -357,27 +367,28 @@ printNix = iterNValueNF (const "") phi <|> (fmap (surround . show) (readMaybe v :: Maybe Float)) ) where surround s = "\"" ++ s ++ "\"" - phi NVClosure{} = "<>" - phi (NVPath fp ) = fp - phi (NVBuiltin name _) = "<>" + phi NVClosure'{} = "<>" + phi (NVPath' fp ) = fp + phi (NVBuiltin' name _) = "<>" phi _ = error "Pattern synonyms foil completeness check" prettyNValue :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => NValue t f m -> m (Doc ann) -prettyNValue = fmap prettyNValueNF . removeEffectsM +prettyNValue = fmap prettyNValueNF . removeEffects prettyNValueProv :: forall t f m ann - . ( HasCitations1 t m (NValue t f m) f + . ( HasCitations m (NValue t f m) t + , HasCitations1 m (NValue t f m) f , MonadThunk t m (NValue t f m) , MonadDataContext f m ) => NValue t f m -> m (Doc ann) -prettyNValueProv v@(NValue nv) = do - let ps = citations1 @t @m @(NValue t f m) @f nv +prettyNValueProv v = do + let ps = citations @m @(NValue t f m) v case ps of [] -> prettyNValue v ps -> do @@ -394,15 +405,15 @@ prettyNValueProv v@(NValue nv) = do prettyNThunk :: forall t f m ann - . ( HasCitations t m (NValue t f m) t - , HasCitations1 t m (NValue t f m) f + . ( HasCitations m (NValue t f m) t + , HasCitations1 m (NValue t f m) f , MonadThunk t m (NValue t f m) , MonadDataContext f m ) => t -> m (Doc ann) prettyNThunk t = do - let ps = citations @t @m @(NValue t f m) @t t + let ps = citations @m @(NValue t f m) @t t v' <- prettyNValueNF <$> dethunk t pure $ fillSep diff --git a/src/Nix/Scope.hs b/src/Nix/Scope.hs index ae44247..9e89eac 100644 --- a/src/Nix/Scope.hs +++ b/src/Nix/Scope.hs @@ -20,64 +20,64 @@ import Data.Text ( Text ) import Lens.Family2 import Nix.Utils -newtype Scope t = Scope { getScope :: AttrSet t } +newtype Scope a = Scope { getScope :: AttrSet a } deriving (Functor, Foldable, Traversable, Eq) -instance Show (Scope t) where +instance Show (Scope a) where show (Scope m) = show (M.keys m) -newScope :: AttrSet t -> Scope t +newScope :: AttrSet a -> Scope a newScope = Scope -scopeLookup :: Text -> [Scope t] -> Maybe t +scopeLookup :: Text -> [Scope a] -> Maybe a scopeLookup key = foldr go Nothing where go (Scope m) rest = M.lookup key m <|> rest -data Scopes m t = Scopes - { lexicalScopes :: [Scope t] - , dynamicScopes :: [m (Scope t)] +data Scopes m a = Scopes + { lexicalScopes :: [Scope a] + , dynamicScopes :: [m (Scope a)] } -instance Show (Scopes m t) where - show (Scopes m t) = - "Scopes: " ++ show m ++ ", and " ++ show (length t) ++ " with-scopes" +instance Show (Scopes m a) where + show (Scopes m a) = + "Scopes: " ++ show m ++ ", and " ++ show (length a) ++ " with-scopes" -instance Semigroup (Scopes m t) where +instance Semigroup (Scopes m a) where Scopes ls lw <> Scopes rs rw = Scopes (ls <> rs) (lw <> rw) -instance Monoid (Scopes m t) where +instance Monoid (Scopes m a) where mempty = emptyScopes mappend = (<>) -emptyScopes :: forall m t . Scopes m t +emptyScopes :: forall m a . Scopes m a emptyScopes = Scopes [] [] -class Scoped t m | m -> t where - currentScopes :: m (Scopes m t) - clearScopes :: m a -> m a - pushScopes :: Scopes m t -> m a -> m a - lookupVar :: Text -> m (Maybe t) +class Scoped a m | m -> a where + currentScopes :: m (Scopes m a) + clearScopes :: m r -> m r + pushScopes :: Scopes m a -> m r -> m r + lookupVar :: Text -> m (Maybe a) currentScopesReader - :: forall m t e . (MonadReader e m, Has e (Scopes m t)) => m (Scopes m t) + :: forall m a e . (MonadReader e m, Has e (Scopes m a)) => m (Scopes m a) currentScopesReader = asks (view hasLens) clearScopesReader - :: forall m t e a . (MonadReader e m, Has e (Scopes m t)) => m a -> m a -clearScopesReader = local (set hasLens (emptyScopes @m @t)) + :: forall m a e r . (MonadReader e m, Has e (Scopes m a)) => m r -> m r +clearScopesReader = local (set hasLens (emptyScopes @m @a)) -pushScope :: Scoped t m => AttrSet t -> m a -> m a +pushScope :: Scoped a m => AttrSet a -> m r -> m r pushScope s = pushScopes (Scopes [Scope s] []) -pushWeakScope :: (Functor m, Scoped t m) => m (AttrSet t) -> m a -> m a +pushWeakScope :: (Functor m, Scoped a m) => m (AttrSet a) -> m r -> m r pushWeakScope s = pushScopes (Scopes [] [Scope <$> s]) pushScopesReader - :: (MonadReader e m, Has e (Scopes m t)) => Scopes m t -> m a -> m a + :: (MonadReader e m, Has e (Scopes m a)) => Scopes m a -> m r -> m r pushScopesReader s = local (over hasLens (s <>)) lookupVarReader - :: forall m t e . (MonadReader e m, Has e (Scopes m t)) => Text -> m (Maybe t) + :: forall m a e . (MonadReader e m, Has e (Scopes m a)) => Text -> m (Maybe a) lookupVarReader k = do mres <- asks (scopeLookup k . lexicalScopes @m . view hasLens) case mres of @@ -94,5 +94,5 @@ lookupVarReader k = do (return Nothing) ws -withScopes :: Scoped t m => Scopes m t -> m a -> m a +withScopes :: Scoped a m => Scopes m a -> m r -> m r withScopes scope = clearScopes . pushScopes scope diff --git a/src/Nix/Thunk.hs b/src/Nix/Thunk.hs index ddbc376..f8e630d 100644 --- a/src/Nix/Thunk.hs +++ b/src/Nix/Thunk.hs @@ -29,18 +29,15 @@ class ( Monad m => m (ThunkId m) freshId = lift freshId -class MonadThunkId m => MonadThunk t m v | t -> m, t -> v where - thunk :: m v -> m t +class MonadThunkId m => MonadThunk t m a | t -> m, t -> a where + thunk :: m a -> m t -- | Return an identifier for the thunk unless it is a pure value (i.e., - -- strictly an encapsulation of some 'v' without any additional + -- strictly an encapsulation of some 'a' without any additional -- structure). For pure values represented as thunks, returns Nothing. - thunkId :: t -> Maybe (ThunkId m) - query :: t -> r -> (v -> r) -> r - queryM :: t -> m r -> (v -> m r) -> m r - force :: t -> (v -> m r) -> m r - forceEff :: t -> (v -> m r) -> m r - wrapValue :: v -> t - getValue :: t -> Maybe v + thunkId :: t -> ThunkId m + queryM :: t -> m r -> (a -> m r) -> m r + force :: t -> (a -> m r) -> m r + forceEff :: t -> (a -> m r) -> m r newtype ThunkLoop = ThunkLoop String -- contains rendering of ThunkId deriving Typeable diff --git a/src/Nix/Thunk/Basic.hs b/src/Nix/Thunk/Basic.hs index e440540..bb044bb 100644 --- a/src/Nix/Thunk/Basic.hs +++ b/src/Nix/Thunk/Basic.hs @@ -27,16 +27,12 @@ data Deferred m v = Deferred (m v) | Computed v -- | The type of very basic thunks data NThunkF m v - = Value v - | Thunk (ThunkId m) (Var m Bool) (Var m (Deferred m v)) + = Thunk (ThunkId m) (Var m Bool) (Var m (Deferred m v)) instance (Eq v, Eq (ThunkId m)) => Eq (NThunkF m v) where - Value x == Value y = x == y Thunk x _ _ == Thunk y _ _ = x == y - _ == _ = False -- jww (2019-03-16): not accurate... instance Show v => Show (NThunkF m v) where - show (Value v ) = show v show (Thunk _ _ _) = "" type MonadBasicThunk m = (MonadThunkId m, MonadVar m) @@ -44,34 +40,17 @@ type MonadBasicThunk m = (MonadThunkId m, MonadVar m) instance (MonadBasicThunk m, MonadCatch m) => MonadThunk (NThunkF m v) m v where thunk = buildThunk - thunkId = \case - Value _ -> Nothing - Thunk n _ _ -> Just n - query = queryValue + thunkId (Thunk n _ _) = n queryM = queryThunk force = forceThunk forceEff = forceEffects - wrapValue = valueRef - getValue = thunkValue - -valueRef :: v -> NThunkF m v -valueRef = Value - -thunkValue :: NThunkF m v -> Maybe v -thunkValue (Value v) = Just v -thunkValue _ = Nothing buildThunk :: MonadBasicThunk m => m v -> m (NThunkF m v) buildThunk action = do freshThunkId <- freshId Thunk freshThunkId <$> newVar False <*> newVar (Deferred action) -queryValue :: MonadVar m => NThunkF m v -> a -> (v -> a) -> a -queryValue (Value v) _ k = k v -queryValue _ n _ = n - queryThunk :: MonadVar m => NThunkF m v -> m a -> (v -> m a) -> m a -queryThunk (Value v ) _ k = k v queryThunk (Thunk _ active ref) n k = do nowActive <- atomicModifyVar active (True, ) if nowActive @@ -90,7 +69,6 @@ forceThunk => NThunkF m v -> (v -> m a) -> m a -forceThunk (Value v ) k = k v forceThunk (Thunk n active ref) k = do eres <- readVar ref case eres of @@ -109,7 +87,6 @@ forceThunk (Thunk n active ref) k = do k v forceEffects :: MonadVar m => NThunkF m v -> (v -> m r) -> m r -forceEffects (Value v ) k = k v forceEffects (Thunk _ active ref) k = do nowActive <- atomicModifyVar active (True, ) if nowActive diff --git a/src/Nix/Utils.hs b/src/Nix/Utils.hs index 5eec404..d13b8ec 100644 --- a/src/Nix/Utils.hs +++ b/src/Nix/Utils.hs @@ -15,6 +15,8 @@ module Nix.Utils (module Nix.Utils, module X) where import Control.Arrow ( (&&&) ) import Control.Monad import Control.Monad.Fix +import Control.Monad.Free +import Control.Monad.Trans.Control ( MonadTransControl(..) ) import qualified Data.Aeson as A import qualified Data.Aeson.Encoding as A import Data.Fix @@ -28,6 +30,7 @@ import Data.Monoid ( Endo import Data.Text ( Text ) import qualified Data.Text as Text import qualified Data.Vector as V +import Data.Void import Lens.Family2 as X import Lens.Family2.Stock ( _1 , _2 @@ -90,6 +93,25 @@ cataPM f x = f x <=< traverse (cataPM f) . unFix $ x transport :: Functor g => (forall x . f x -> g x) -> Fix f -> Fix g transport f (Fix x) = Fix $ fmap (transport f) (f x) +lifted + :: ( MonadTransControl u + , Monad (u m) + , Monad m + ) + => ((a -> m (StT u b)) -> m (StT u b)) -> (a -> u m b) -> u m b +lifted f k = liftWith (\run -> f (run . k)) >>= restoreT . return + +freeToFix :: Functor f => (a -> Fix f) -> Free f a -> Fix f +freeToFix f = go + where + go (Pure a) = f a + go (Free v) = Fix (fmap go v) + +fixToFree :: Functor f => Fix f -> Free f Void +fixToFree = Free . go + where + go (Fix f) = fmap (Free . go) f + -- | adi is Abstracting Definitional Interpreters: -- -- https://arxiv.org/abs/1707.04755 diff --git a/src/Nix/Value.hs b/src/Nix/Value.hs index 8e2fbc4..c323bcb 100644 --- a/src/Nix/Value.hs +++ b/src/Nix/Value.hs @@ -36,10 +36,12 @@ import Control.Monad import Control.Monad.Free import Control.Monad.Trans.Class import qualified Data.Aeson as A +import Data.Fix import Data.Functor.Classes import Data.HashMap.Lazy ( HashMap ) import Data.Text ( Text ) import Data.Typeable ( Typeable ) +import Data.Void import GHC.Generics import Lens.Family2 import Lens.Family2.Stock @@ -62,7 +64,7 @@ data NValueF p m r | NVPathF FilePath | NVListF [r] | NVSetF (AttrSet r) (AttrSet SourcePos) - | NVClosureF (Params ()) (m p -> m r) + | NVClosureF (Params ()) (p -> m r) -- ^ A function is a closed set of parameters representing the "call -- signature", used at application time to check the type of arguments -- passed to the function. Since it supports default values which may @@ -74,7 +76,7 @@ data NValueF p m r -- Note that 'm r' is being used here because effectively a function -- and its set of default arguments is "never fully evaluated". This -- enforces in the type that it must be re-evaluated for each call. - | NVBuiltinF String (m p -> m r) + | NVBuiltinF String (p -> m r) -- ^ A builtin function is itself already in normal form. Also, it may -- or may not choose to evaluate its argument in the production of a -- result. @@ -92,6 +94,20 @@ instance Foldable (NValueF p m) where NVClosureF _ _ -> mempty NVBuiltinF _ _ -> mempty +instance Show r => Show (NValueF p m r) where + showsPrec = flip go where + go (NVConstantF atom ) = showsCon1 "NVConstant" atom + go (NVStrF ns ) = showsCon1 "NVStr" (hackyStringIgnoreContext ns) + go (NVListF lst ) = showsCon1 "NVList" lst + go (NVSetF attrs _) = showsCon1 "NVSet" attrs + go (NVClosureF p _) = showsCon1 "NVClosure" p + go (NVPathF p ) = showsCon1 "NVPath" p + go (NVBuiltinF name _ ) = showsCon1 "NVBuiltin" name + + showsCon1 :: Show a => String -> a -> Int -> String -> String + showsCon1 con a d = + showParen (d > 10) $ showString (con ++ " ") . showsPrec 11 a + lmapNValueF :: Functor m => (b -> a) -> NValueF a m r -> NValueF b m r lmapNValueF f = \case NVConstantF a -> NVConstantF a @@ -99,22 +115,21 @@ lmapNValueF f = \case NVPathF p -> NVPathF p NVListF l -> NVListF l NVSetF s p -> NVSetF s p - NVClosureF p g -> NVClosureF p (g . fmap f) - NVBuiltinF s g -> NVBuiltinF s (g . fmap f) + NVClosureF p g -> NVClosureF p (g . f) + NVBuiltinF s g -> NVBuiltinF s (g . f) hoistNValueF - :: (forall x . n x -> m x) - -> (forall x . m x -> n x) + :: (forall x . m x -> n x) -> NValueF p m a -> NValueF p n a -hoistNValueF run lft = \case +hoistNValueF lft = \case NVConstantF a -> NVConstantF a NVStrF s -> NVStrF s NVPathF p -> NVPathF p NVListF l -> NVListF l NVSetF s p -> NVSetF s p - NVClosureF p g -> NVClosureF p (lft . g . run) - NVBuiltinF s g -> NVBuiltinF s (lft . g . run) + NVClosureF p g -> NVClosureF p (lft . g) + NVBuiltinF s g -> NVBuiltinF s (lft . g) sequenceNValueF :: (Functor n, Monad m, Applicative n) @@ -147,17 +162,16 @@ bindNValueF transform f = \case liftNValueF :: (MonadTrans u, Monad m) - => (forall x . u m x -> m x) - -> NValueF p m a + => NValueF p m a -> NValueF p (u m) a -liftNValueF run = hoistNValueF run lift +liftNValueF = hoistNValueF lift unliftNValueF :: (MonadTrans u, Monad m) => (forall x . u m x -> m x) -> NValueF p (u m) a -> NValueF p m a -unliftNValueF run = hoistNValueF lift run +unliftNValueF = hoistNValueF type MonadDataContext f (m :: * -> *) = (Comonad f, Applicative f, Traversable f, Monad m) @@ -167,76 +181,69 @@ type MonadDataContext f (m :: * -> *) newtype NValue' t f m a = NValue { _nValue :: f (NValueF (NValue t f m) m a) } deriving (Generic, Typeable, Functor, Foldable) -instance Show r => Show (NValueF p m r) where - showsPrec = flip go where - go (NVConstantF atom ) = showsCon1 "NVConstant" atom - go (NVStrF ns ) = showsCon1 "NVStr" (hackyStringIgnoreContext ns) - go (NVListF lst ) = showsCon1 "NVList" lst - go (NVSetF attrs _) = showsCon1 "NVSet" attrs - go (NVClosureF p _) = showsCon1 "NVClosure" p - go (NVPathF p ) = showsCon1 "NVPath" p - go (NVBuiltinF name _ ) = showsCon1 "NVBuiltin" name - - showsCon1 :: Show a => String -> a -> Int -> String -> String - showsCon1 con a d = - showParen (d > 10) $ showString (con ++ " ") . showsPrec 11 a - instance (Comonad f, Show a) => Show (NValue' t f m a) where show (NValue (extract -> v)) = show v instance Comonad f => Show1 (NValue' t f m) where liftShowsPrec sp sl p = \case - NVConstant atom -> showsUnaryWith showsPrec "NVConstantF" p atom - NVStr ns -> + NVConstant' atom -> showsUnaryWith showsPrec "NVConstantF" p atom + NVStr' ns -> showsUnaryWith showsPrec "NVStrF" p (hackyStringIgnoreContext ns) - NVList lst -> showsUnaryWith (liftShowsPrec sp sl) "NVListF" p lst - NVSet attrs _ -> showsUnaryWith (liftShowsPrec sp sl) "NVSetF" p attrs - NVPath path -> showsUnaryWith showsPrec "NVPathF" p path - NVClosure c _ -> showsUnaryWith showsPrec "NVClosureF" p c - NVBuiltin name _ -> showsUnaryWith showsPrec "NVBuiltinF" p name - _ -> error "Pattern synonyms mask coverage" + NVList' lst -> showsUnaryWith (liftShowsPrec sp sl) "NVListF" p lst + NVSet' attrs _ -> showsUnaryWith (liftShowsPrec sp sl) "NVSetF" p attrs + NVPath' path -> showsUnaryWith showsPrec "NVPathF" p path + NVClosure' c _ -> showsUnaryWith showsPrec "NVClosureF" p c + NVBuiltin' name _ -> showsUnaryWith showsPrec "NVBuiltinF" p name + _ -> error "Pattern synonyms mask coverage" -type NValue t f m = NValue' t f m t - -sequenceNValue +sequenceNValue' :: (Functor n, Traversable f, Monad m, Applicative n) => (forall x . n x -> m x) -> NValue' t f m (n a) -> n (NValue' t f m a) -sequenceNValue transform (NValue v) = +sequenceNValue' transform (NValue v) = NValue <$> traverse (sequenceNValueF transform) v -bindNValue +bindNValue' :: (Traversable f, Monad m, Monad n) => (forall x . n x -> m x) -> (a -> n b) -> NValue' t f m a -> n (NValue' t f m b) -bindNValue transform f (NValue v) = +bindNValue' transform f (NValue v) = NValue <$> traverse (bindNValueF transform f) v -hoistNValue +hoistNValue' :: (Functor m, Functor n, Functor f) => (forall x . n x -> m x) -> (forall x . m x -> n x) -> NValue' t f m a -> NValue' t f n a -hoistNValue run lft (NValue v) = - NValue (fmap (lmapNValueF (hoistNValue lft run) . hoistNValueF run lft) v) +hoistNValue' run lft (NValue v) = + NValue (fmap (lmapNValueF (hoistNValue lft run) . hoistNValueF lft) v) -liftNValue +liftNValue' :: (MonadTrans u, Monad m, Functor (u m), Functor f) => (forall x . u m x -> m x) -> NValue' t f m a -> NValue' t f (u m) a -liftNValue run = hoistNValue run lift +liftNValue' run = hoistNValue' run lift -unliftNValue +unliftNValue' :: (MonadTrans u, Monad m, Functor (u m), Functor f) => (forall x . u m x -> m x) -> NValue' t f (u m) a -> NValue' t f m a -unliftNValue run = hoistNValue lift run +unliftNValue' run = hoistNValue' lift run + +iterNValue' + :: forall t f m a r + . MonadDataContext f m + => (a -> (NValue' t f m a -> r) -> r) + -> (NValue' t f m r -> r) + -> NValue' t f m a + -> r +iterNValue' k f = f . fmap (\a -> k a (iterNValue' k f)) -- | An 'NValueNF' is a fully evaluated value in normal form. An 'NValue f t m' is -- a value in head normal form, where only the "top layer" has been @@ -248,64 +255,72 @@ unliftNValue run = hoistNValue lift run -- The 'Free' structure is used here to represent the possibility that -- cycles may appear during normalization. -type NValueNF t f m = Free (NValue' t f m) t +type NValue t f m = Free (NValue' t f m) t +type NValueNF t f m = Fix (NValue' t f m) + +hoistNValue + :: (Functor m, Functor n, Functor f) + => (forall x . n x -> m x) + -> (forall x . m x -> n x) + -> NValue t f m + -> NValue t f n +hoistNValue run lft = hoistFree (hoistNValue' run lft) + +liftNValue + :: (MonadTrans u, Monad m, Functor (u m), Functor f) + => (forall x . u m x -> m x) + -> NValue t f m + -> NValue t f (u m) +liftNValue run = hoistNValue run lift + +unliftNValue + :: (MonadTrans u, Monad m, Functor (u m), Functor f) + => (forall x . u m x -> m x) + -> NValue t f (u m) + -> NValue t f m +unliftNValue run = hoistNValue lift run iterNValue - :: forall t f m a r + :: forall t f m r . MonadDataContext f m - => (a -> (NValue' t f m a -> r) -> r) + => (t -> (NValue t f m -> r) -> r) -> (NValue' t f m r -> r) - -> NValue' t f m a + -> NValue t f m -> r -iterNValue k f = f . fmap (\a -> k a (iterNValue k f)) +iterNValue k f = iter f . fmap (\t -> k t (iterNValue k f)) iterNValueM :: (MonadDataContext f m, Monad n) => (forall x . n x -> m x) - -> (a -> (NValue' t f m a -> n r) -> n r) - -> (NValue' t f m r -> n r) - -> NValue' t f m a + -> (t -> (NValue t f m -> n r) -> n r) + -> (NValue' t f m (n r) -> n r) + -> NValue t f m -> n r iterNValueM transform k f = - f <=< bindNValue transform (\a -> k a (iterNValueM transform k f)) + iterM f <=< go . fmap (\t -> k t (iterNValueM transform k f)) + where + go (Pure x) = Pure <$> x + go (Free fa) = Free <$> bindNValue' transform go fa iterNValueNF :: MonadDataContext f m - => (t -> r) - -> (NValue' t f m r -> r) + => (NValue' t f m r -> r) -> NValueNF t f m -> r -iterNValueNF k f = iter f . fmap k - -iterNValueNFM - :: forall f m n t r - . (MonadDataContext f m, Monad n) - => (forall x . n x -> m x) - -> (t -> n r) - -> (NValue' t f m (n r) -> n r) - -> NValueNF t f m - -> n r -iterNValueNFM transform k f v = - iterM f =<< go (fmap k v) - where - go (Pure a ) = Pure <$> a - go (Free fa) = Free <$> bindNValue transform go fa +iterNValueNF = cata nValueFromNF :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => NValueNF t f m -> NValue t f m -nValueFromNF = iterNValueNF f (fmap wrapValue) - where - f t = query t cyc id - cyc = nvStr (principledMakeNixStringWithoutContext "") +nValueFromNF = fmap absurd . fixToFree nValueToNF :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => (t -> (NValue t f m -> NValueNF t f m) -> NValueNF t f m) -> NValue t f m -> NValueNF t f m -nValueToNF k = iterNValue k Free +nValueToNF k = iterNValue k Fix nValueToNFM :: (MonadDataContext f m, Monad n) @@ -313,91 +328,124 @@ nValueToNFM -> (t -> (NValue t f m -> n (NValueNF t f m)) -> n (NValueNF t f m)) -> NValue t f m -> n (NValueNF t f m) -nValueToNFM transform k = iterNValueM transform k $ pure . Free +nValueToNFM transform k = iterNValueM transform k undefined -pattern NVConstant x <- NValue (extract -> NVConstantF x) -pattern NVConstantNF x <- Free (NValue (extract -> NVConstantF x)) +pattern NVThunk t <- Pure t +nvThunk :: Applicative f => t -> NValue t f m +nvThunk = Pure + +pattern NVConstant' x <- NValue (extract -> NVConstantF x) +pattern NVConstant x <- Free (NVConstant' x) +pattern NVConstantNF x <- Fix (NVConstant' x) + +nvConstant' :: Applicative f => NAtom -> NValue' t f m r +nvConstant' x = NValue (pure (NVConstantF x)) nvConstant :: Applicative f => NAtom -> NValue t f m -nvConstant x = NValue (pure (NVConstantF x)) +nvConstant x = Free (NValue (pure (NVConstantF x))) nvConstantNF :: Applicative f => NAtom -> NValueNF t f m -nvConstantNF x = Free (NValue (pure (NVConstantF x))) +nvConstantNF x = Fix (NValue (pure (NVConstantF x))) -pattern NVStr ns <- NValue (extract -> NVStrF ns) -pattern NVStrNF ns <- Free (NValue (extract -> NVStrF ns)) +pattern NVStr' ns <- NValue (extract -> NVStrF ns) +pattern NVStr ns <- Free (NVStr' ns) +pattern NVStrNF ns <- Fix (NVStr' ns) +nvStr' :: Applicative f => NixString -> NValue' t f m r +nvStr' ns = NValue (pure (NVStrF ns)) nvStr :: Applicative f => NixString -> NValue t f m -nvStr ns = NValue (pure (NVStrF ns)) +nvStr ns = Free (NValue (pure (NVStrF ns))) nvStrNF :: Applicative f => NixString -> NValueNF t f m -nvStrNF ns = Free (NValue (pure (NVStrF ns))) +nvStrNF ns = Fix (NValue (pure (NVStrF ns))) -pattern NVPath x <- NValue (extract -> NVPathF x) -pattern NVPathNF x <- Free (NValue (extract -> NVPathF x)) +pattern NVPath' x <- NValue (extract -> NVPathF x) +pattern NVPath x <- Free (NVPath' x) +pattern NVPathNF x <- Fix (NVPath' x) +nvPath' :: Applicative f => FilePath -> NValue' t f m r +nvPath' x = NValue (pure (NVPathF x)) nvPath :: Applicative f => FilePath -> NValue t f m -nvPath x = NValue (pure (NVPathF x)) +nvPath x = Free (NValue (pure (NVPathF x))) nvPathNF :: Applicative f => FilePath -> NValueNF t f m -nvPathNF x = Free (NValue (pure (NVPathF x))) +nvPathNF x = Fix (NValue (pure (NVPathF x))) -pattern NVList l <- NValue (extract -> NVListF l) -pattern NVListNF l <- Free (NValue (extract -> NVListF l)) +pattern NVList' l <- NValue (extract -> NVListF l) +pattern NVList l <- Free (NVList' l) +pattern NVListNF l <- Fix (NVList' l) -nvList :: Applicative f => [t] -> NValue t f m -nvList l = NValue (pure (NVListF l)) +nvList' :: Applicative f => [r] -> NValue' t f m r +nvList' l = NValue (pure (NVListF l)) +nvList :: Applicative f => [NValue t f m] -> NValue t f m +nvList l = Free (NValue (pure (NVListF l))) nvListNF :: Applicative f => [NValueNF t f m] -> NValueNF t f m -nvListNF l = Free (NValue (pure (NVListF l))) +nvListNF l = Fix (NValue (pure (NVListF l))) -pattern NVSet s x <- NValue (extract -> NVSetF s x) -pattern NVSetNF s x <- Free (NValue (extract -> NVSetF s x)) +pattern NVSet' s x <- NValue (extract -> NVSetF s x) +pattern NVSet s x <- Free (NVSet' s x) +pattern NVSetNF s x <- Fix (NVSet' s x) +nvSet' :: Applicative f + => HashMap Text r -> HashMap Text SourcePos -> NValue' t f m r +nvSet' s x = NValue (pure (NVSetF s x)) nvSet :: Applicative f - => HashMap Text t -> HashMap Text SourcePos -> NValue t f m -nvSet s x = NValue (pure (NVSetF s x)) + => HashMap Text (NValue t f m) -> HashMap Text SourcePos -> NValue t f m +nvSet s x = Free (NValue (pure (NVSetF s x))) nvSetNF :: Applicative f - => HashMap Text (NValueNF t f m) -> HashMap Text SourcePos -> NValueNF t f m -nvSetNF s x = Free (NValue (pure (NVSetF s x))) + => HashMap Text (NValueNF t f m) -> HashMap Text SourcePos + -> NValueNF t f m +nvSetNF s x = Fix (NValue (pure (NVSetF s x))) -pattern NVClosure x f <- NValue (extract -> NVClosureF x f) -pattern NVClosureNF x f <- Free (NValue (extract -> NVClosureF x f)) +pattern NVClosure' x f <- NValue (extract -> NVClosureF x f) +pattern NVClosure x f <- Free (NVClosure' x f) +pattern NVClosureNF x f <- Fix (NVClosure' x f) -nvClosure :: Applicative f - => Params () -> (m (NValue t f m) -> m t) -> NValue t f m -nvClosure x f = NValue (pure (NVClosureF x f)) +nvClosure' :: (Applicative f, Functor m) + => Params () -> (NValue t f m -> m r) -> NValue' t f m r +nvClosure' x f = NValue (pure (NVClosureF x f)) +nvClosure :: (Applicative f, Functor m) + => Params () -> (NValue t f m -> m (NValue t f m)) -> NValue t f m +nvClosure x f = Free (NValue (pure (NVClosureF x f))) nvClosureNF :: Applicative f - => Params () -> (m (NValue t f m) -> m (NValueNF t f m)) -> NValueNF t f m -nvClosureNF x f = Free (NValue (pure (NVClosureF x f))) + => Params () -> (NValue t f m -> m (NValueNF t f m)) + -> NValueNF t f m +nvClosureNF x f = Fix (NValue (pure (NVClosureF x f))) -pattern NVBuiltin name f <- NValue (extract -> NVBuiltinF name f) -pattern NVBuiltinNF name f <- Free (NValue (extract -> NVBuiltinF name f)) +pattern NVBuiltin' name f <- NValue (extract -> NVBuiltinF name f) +pattern NVBuiltin name f <- Free (NVBuiltin' name f) +pattern NVBuiltinNF name f <- Fix (NVBuiltin' name f) -nvBuiltin :: Applicative f - => String -> (m (NValue t f m) -> m t) -> NValue t f m -nvBuiltin name f = NValue (pure (NVBuiltinF name f)) +nvBuiltin' :: (Applicative f, Functor m) + => String -> (NValue t f m -> m r) -> NValue' t f m r +nvBuiltin' name f = NValue (pure (NVBuiltinF name f)) +nvBuiltin :: (Applicative f, Functor m) + => String -> (NValue t f m -> m (NValue t f m)) -> NValue t f m +nvBuiltin name f = + Free (NValue (pure (NVBuiltinF name f))) nvBuiltinNF :: Applicative f - => String -> (m (NValue t f m) -> m (NValueNF t f m)) -> NValueNF t f m -nvBuiltinNF name f = Free (NValue (pure (NVBuiltinF name f))) + => String -> (NValue t f m -> m (NValueNF t f m)) + -> NValueNF t f m +nvBuiltinNF name f = Fix (NValue (pure (NVBuiltinF name f))) builtin :: forall m f t . (MonadThunk t m (NValue t f m), MonadDataContext f m) => String - -> (m (NValue t f m) -> m (NValue t f m)) + -> (NValue t f m -> m (NValue t f m)) -> m (NValue t f m) -builtin name f = return $ nvBuiltin name $ \a -> thunk $ f a +builtin name f = return $ nvBuiltin name $ \a -> f a builtin2 :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => String - -> (m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m)) + -> (NValue t f m -> NValue t f m -> m (NValue t f m)) -> m (NValue t f m) builtin2 name f = builtin name $ \a -> builtin name $ \b -> f a b builtin3 :: (MonadThunk t m (NValue t f m), MonadDataContext f m) => String - -> ( m (NValue t f m) - -> m (NValue t f m) - -> m (NValue t f m) + -> ( NValue t f m + -> NValue t f m + -> NValue t f m -> m (NValue t f m) ) -> m (NValue t f m) @@ -454,7 +502,7 @@ describeValue = \case TBuiltin -> "a builtin function" data ValueFrame t f m - = ForcingThunk + = ForcingThunk t | ConcerningValue (NValue t f m) | Comparison (NValue t f m) (NValue t f m) | Addition (NValue t f m) (NValue t f m) @@ -463,9 +511,10 @@ data ValueFrame t f m | Coercion ValueType ValueType | CoercionToJson (NValue t f m) | CoercionFromJson A.Value - | ExpectationNF ValueType (NValueNF t f m) - | Expectation ValueType (NValue t f m) - deriving (Show, Typeable) + | forall r. Show r => Expectation ValueType (NValue' t f m r) + deriving Typeable + +deriving instance (Comonad f, Show t) => Show (ValueFrame t f m) type MonadDataErrorContext t f m = (Show t, Typeable t, Typeable m, Typeable f, MonadDataContext f m) diff --git a/src/Nix/Value/Equal.hs b/src/Nix/Value/Equal.hs index 6f380a9..a202e2b 100644 --- a/src/Nix/Value/Equal.hs +++ b/src/Nix/Value/Equal.hs @@ -38,6 +38,7 @@ import Control.Monad.Trans.Class import Control.Monad.Trans.Except import Data.Align import Data.Eq.Deriving +import Data.Fix import Data.Functor.Classes import Data.Functor.Identity import qualified Data.HashMap.Lazy as M @@ -164,30 +165,30 @@ compareAttrSets f eq lm rm = runIdentity $ compareAttrSetsM (\t -> Identity (f t)) (\x y -> Identity (eq x y)) lm rm valueEqM - :: (MonadThunk t m (NValue t f m), Comonad f) + :: forall t f m. (MonadThunk t m (NValue t f m), Comonad f) => NValue t f m -> NValue t f m -> m Bool -valueEqM (NValue (extract -> x)) (NValue (extract -> y)) = valueFEqM - (compareAttrSetsM f thunkEqM) - thunkEqM - x - y - where - f t = force t $ \case +valueEqM (Pure x) (Pure y) = thunkEqM x y +valueEqM (Pure _) _ = pure False +valueEqM _ (Pure _) = pure False +valueEqM (Free (NValue (extract -> x))) (Free (NValue (extract -> y))) = + valueFEqM (compareAttrSetsM f valueEqM) valueEqM x y + where + f (Pure t) = force t $ \case NVStr s -> pure $ Just s _ -> pure Nothing + f (Free v) = case v of + NVStr' s -> pure $ Just s + _ -> pure Nothing valueNFEq :: Comonad f => NValueNF t f m -> NValueNF t f m -> Bool -valueNFEq (Pure _) (Pure _) = False -valueNFEq (Pure _) (Free _) = False -valueNFEq (Free _) (Pure _) = False -valueNFEq (Free (NValue (extract -> x))) (Free (NValue (extract -> y))) = +valueNFEq (Fix (NValue (extract -> x))) (Fix (NValue (extract -> y))) = valueFEq (compareAttrSets f valueNFEq) valueNFEq x y where - f (Pure _ ) = Nothing - f (Free (NVStr s)) = Just s - f _ = Nothing + f = \case + NVStrNF s -> Just s + _ -> Nothing instance Eq1 (NValueF p m) where liftEq _ (NVConstantF x) (NVConstantF y) = x == y diff --git a/src/Nix/Value/Monad.hs b/src/Nix/Value/Monad.hs new file mode 100644 index 0000000..c2cda12 --- /dev/null +++ b/src/Nix/Value/Monad.hs @@ -0,0 +1,8 @@ +{-# LANGUAGE FunctionalDependencies #-} +{-# LANGUAGE MultiParamTypeClasses #-} + +module Nix.Value.Monad where + +class MonadValue v m where + defer :: m v -> m v + demand :: v -> (v -> m r) -> m r