Skip to content

Commit

Permalink
Add a builder for unrestricted monads
Browse files Browse the repository at this point in the history
  • Loading branch information
aspiwack committed Aug 10, 2018
1 parent 59f6096 commit 762d18c
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 21 deletions.
1 change: 1 addition & 0 deletions linear-base.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ cabal-version: >=1.10
library
hs-source-dirs: src
exposed-modules:
Control.Monad.Builder
Control.Monad.Linear
Control.Monad.Linear.Builder
Foreign.Marshal.Pure
Expand Down
35 changes: 35 additions & 0 deletions src/Control/Monad/Builder.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes #-}

module Control.Monad.Builder
( BuilderType(..)
, monadBuilder
) where

-- TODO: Link to example of builder

import qualified Control.Monad as Unrestricted hiding (fail)
import qualified Control.Monad.Fail as Unrestricted
import Prelude.Linear (String)

-- | Type of 'monadBuilder'. Note how the constraint on @m@ varies depending on
-- the field. The constraints are solved lazily when a field is used by the do
-- notation (in particular, if you don't do a pattern-matching, then you don't
-- need a 'LMonadFail').
data BuilderType = Builder
{ (>>=) :: forall m a b. Unrestricted.Monad m => m a -> (a -> m b) -> m b
, (>>) :: forall m b. Unrestricted.Monad m => m () -> m b -> m b
, fail :: forall m a. Unrestricted.MonadFail m => String -> m a
, return :: forall m a. Unrestricted.Monad m => a -> m a
-- See also 'Control.Monad.Linear.Builder.return'
}

-- | A builder to be used with @-XRebindableSyntax@ in conjunction with
-- @RecordWildCards@
monadBuilder :: BuilderType
monadBuilder = Builder
{ (>>=) = (Unrestricted.>>=)
, (>>) = (Unrestricted.>>)
, fail = Unrestricted.fail
, return = Unrestricted.return }
30 changes: 9 additions & 21 deletions src/System/IO/Resource.hs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ module System.IO.Resource
) where

import Control.Exception (onException, mask, finally)
import Control.Monad (fmap, fail)
-- XXX: ^ should be imported qualified. Fail should be made available in a
-- builder.
import qualified Control.Monad as Unrestricted (fmap)
import qualified Control.Monad.Builder as Unrestricted
import qualified Control.Monad.Linear as Linear
import qualified Control.Monad.Linear.Builder as Linear
import Data.Coerce
Expand All @@ -55,10 +54,6 @@ import Data.Text (Text)
import qualified Data.Text.IO as Text
import Prelude.Linear hiding (IO, ($))
import Prelude (($))
import qualified Prelude as P
-- XXX: ^ is only imported for a few monadic primitives. Should be replaced by
-- importing Control.Monad qualified (for return) and a generic builder for
-- monads.
import qualified System.IO.Linear as Linear
import qualified System.IO as System

Expand All @@ -78,20 +73,16 @@ run (RIO action) = do
(restore (Linear.withLinearIO (action rrm)))
(do -- release stray resources
ReleaseMap releaseMap <- System.readIORef rrm
safeRelease (fmap snd (IntMap.toList releaseMap))))
safeRelease $ Unrestricted.fmap snd $ IntMap.toList releaseMap))
-- Remarks: resources are guaranteed to be released on non-exceptional
-- return. So, contrary to a standard bracket/ResourceT implementation, we
-- only release exceptions in the release map upon exception.
where
-- XXX: weird return again
return :: Bool
return = True
-- Use regular IO binds
(>>=) :: System.IO a -> (a -> System.IO b) -> (System.IO b)
(>>=) = (P.>>=)
Unrestricted.Builder{..} = Unrestricted.monadBuilder
-- used in the do-notation

safeRelease :: [Linear.IO ()] -> System.IO ()
safeRelease [] = P.return ()
safeRelease [] = return ()
safeRelease (finalizer:fs) = Linear.withLinearIO (moveLinearIO finalizer)
`finally` safeRelease fs
-- Should be just an application of a linear `(<$>)`.
Expand Down Expand Up @@ -238,13 +229,10 @@ unsafeFromSystemIOResource
unsafeFromSystemIOResource action (UnsafeResource key resource) =
unsafeFromSystemIO (do
c <- action resource
P.return (Unrestricted c, UnsafeResource key resource))
return (Unrestricted c, UnsafeResource key resource))
where
return :: ()
return = ()

(>>=) :: System.IO a -> (a -> System.IO b) -> (System.IO b)
(>>=) = (P.>>=)
Unrestricted.Builder{..} = Unrestricted.monadBuilder
-- used in the do-notation

unsafeFromSystemIOResource_
:: (a -> System.IO ())
Expand Down

0 comments on commit 762d18c

Please sign in to comment.