2019-03-11 21:55:40 +01:00
|
|
|
{-# LANGUAGE ConstraintKinds #-}
|
2019-03-11 16:04:15 +01:00
|
|
|
{-# LANGUAGE DeriveFoldable #-}
|
|
|
|
{-# LANGUAGE DeriveFunctor #-}
|
|
|
|
{-# LANGUAGE DeriveTraversable #-}
|
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2019-03-11 21:55:40 +01:00
|
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
2019-03-11 16:04:15 +01:00
|
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
{-# LANGUAGE TupleSections #-}
|
2019-03-11 21:55:40 +01:00
|
|
|
{-# LANGUAGE UndecidableInstances #-}
|
2019-03-11 16:04:15 +01:00
|
|
|
|
|
|
|
{-# OPTIONS_GHC -Wno-orphans #-}
|
|
|
|
|
|
|
|
module Nix.Thunk.Basic where
|
|
|
|
|
|
|
|
import Control.Exception hiding (catch)
|
|
|
|
import Control.Monad.Catch
|
2019-03-11 21:55:40 +01:00
|
|
|
import Control.Monad.Ref
|
|
|
|
import Data.GADT.Compare
|
2019-03-11 16:04:15 +01:00
|
|
|
|
|
|
|
import Nix.Fresh
|
|
|
|
import Nix.Thunk
|
|
|
|
import Nix.Utils
|
|
|
|
import Nix.Var
|
|
|
|
|
|
|
|
data Deferred m v = Deferred (m v) | Computed v
|
|
|
|
deriving (Functor, Foldable, Traversable)
|
|
|
|
|
|
|
|
-- | The type of very basic thunks
|
|
|
|
data NThunkF m v
|
|
|
|
= Value v
|
|
|
|
| Thunk Int (Var m Bool) (Var m (Deferred m v))
|
|
|
|
|
|
|
|
instance Show v => Show (NThunkF m v) where
|
|
|
|
show (Value v) = show v
|
|
|
|
show (Thunk _ _ _) = "<thunk>"
|
|
|
|
|
2019-03-11 21:55:40 +01:00
|
|
|
type MonadBasicThunk m
|
|
|
|
= (MonadAtomicRef m, GEq (Ref m), MonadFreshId Int m, MonadCatch m)
|
|
|
|
|
|
|
|
instance (MonadAtomicRef m, GEq (Ref m), MonadFreshId Int m, MonadCatch m)
|
|
|
|
=> MonadThunk v (NThunkF m v) m where
|
|
|
|
thunk = buildThunk
|
|
|
|
force = forceThunk
|
|
|
|
forceEff = forceEffects
|
|
|
|
wrapValue = valueRef
|
|
|
|
getValue = thunkValue
|
|
|
|
|
2019-03-11 16:04:15 +01:00
|
|
|
valueRef :: v -> NThunkF m v
|
|
|
|
valueRef = Value
|
|
|
|
|
2019-03-11 21:55:40 +01:00
|
|
|
thunkValue :: NThunkF m v -> Maybe v
|
|
|
|
thunkValue (Value v) = Just v
|
|
|
|
thunkValue _ = Nothing
|
|
|
|
|
2019-03-11 16:04:15 +01:00
|
|
|
buildThunk :: (MonadVar m, MonadFreshId Int m) => m v -> m (NThunkF m v)
|
|
|
|
buildThunk action =do
|
|
|
|
freshThunkId <- freshId
|
|
|
|
Thunk freshThunkId <$> newVar False <*> newVar (Deferred action)
|
|
|
|
|
|
|
|
forceThunk :: (MonadVar m, MonadThrow m, MonadCatch m)
|
|
|
|
=> NThunkF m v -> (v -> m a) -> m a
|
|
|
|
forceThunk (Value ref) k = k ref
|
|
|
|
forceThunk (Thunk n active ref) k = do
|
|
|
|
eres <- readVar ref
|
|
|
|
case eres of
|
|
|
|
Computed v -> k v
|
|
|
|
Deferred action -> do
|
|
|
|
nowActive <- atomicModifyVar active (True,)
|
|
|
|
if nowActive
|
|
|
|
then
|
|
|
|
throwM $ ThunkLoop (Just n)
|
|
|
|
else do
|
|
|
|
traceM $ "Forcing " ++ show n
|
|
|
|
v <- catch action $ \(e :: SomeException) -> do
|
|
|
|
_ <- atomicModifyVar active (False,)
|
|
|
|
throwM e
|
|
|
|
_ <- atomicModifyVar active (False,)
|
|
|
|
writeVar ref (Computed v)
|
|
|
|
k v
|
|
|
|
|
|
|
|
forceEffects :: MonadVar m => NThunkF m v -> (v -> m a) -> m a
|
|
|
|
forceEffects (Value ref) k = k ref
|
|
|
|
forceEffects (Thunk _ active ref) k = do
|
|
|
|
nowActive <- atomicModifyVar active (True,)
|
|
|
|
if nowActive
|
|
|
|
then return $ error "forceEffects: a value was expected"
|
|
|
|
else do
|
|
|
|
eres <- readVar ref
|
|
|
|
case eres of
|
|
|
|
Computed v -> k v
|
|
|
|
Deferred action -> do
|
|
|
|
v <- action
|
|
|
|
writeVar ref (Computed v)
|
|
|
|
_ <- atomicModifyVar active (False,)
|
|
|
|
k v
|