Passing around effectful actions #201
-
Sometimes I want to do something like {-# OPTIONS_GHC -Wno-redundant-constraints #-}
module Sandbox () where
import Data.Function ((&))
import Effectful (Eff, IOE, Subset, inject, (:>), runEff, MonadIO (liftIO))
import Effectful.Concurrent (Concurrent, runConcurrent)
import Effectful.FileSystem (FileSystem, runFileSystem)
import Prelude hiding (writeFile)
import Effectful.FileSystem.IO.File (writeBinaryFile)
import qualified Data.ByteString.Char8 as Bs8
import Effectful.Concurrent.MVar.Strict (MVar, putMVar, newEmptyMVar, readMVar)
data Env es = Env {getInitialState :: Eff es Int}
main :: IO ()
main = do
let env :: Env '[IOE] = Env {getInitialState = pure 0}
startServer env
& runConcurrent
& runEff
startServer :: (Concurrent :> es0, IOE :> es0, Subset es1 es0) => Env es1 -> Eff es0 ()
startServer env = do
stateMVar <- newEmptyMVar
getInitialStateWriteState env stateMVar & runFileSystem
-- ^ compile error here
runServer stateMVar
getInitialStateWriteState :: (FileSystem :> es0, Concurrent :> es0, Subset es1 es0) => Env es1 -> MVar Int -> Eff es0 ()
getInitialStateWriteState Env{getInitialState} stateMVar = do
state <- getInitialState & inject
putMVar stateMVar state
writeBinaryFile "state.txt" (Bs8.pack $ show state)
runServer :: (Concurrent :> es, IOE :> es) => MVar Int -> Eff es ()
runServer stateMVar = do
state <- readMVar stateMVar
liftIO $ print state but I get a compile error
which probably comes from the fact that Is there a way to do this or is this kinda thing just avoid and don't put |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
I'm not sure what you're trying to accomplish 🤔 Can you give a more specific example (preferably with a code I can try to compile)? |
Beta Was this translation helpful? Give feedback.
-
You could create an injectEnv :: Subset xs es => Env xs -> Env es
injectEnv env = Env {getInitialState = inject env.getInitialState} And then you don't need to use #!/usr/bin/env nix-shell
#!nix-shell -i ghcid -p ghcid "ghc.withPackages (p: with p; [ effectful effectful-core ])"
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoFieldSelectors #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
module Sandbox () where
import Data.Function ((&))
import Effectful (Eff, IOE, Subset, inject, (:>), runEff, MonadIO (liftIO))
import Effectful.Concurrent (Concurrent, runConcurrent)
import Effectful.FileSystem (FileSystem, runFileSystem)
import Prelude hiding (writeFile)
import Effectful.FileSystem.IO.File (writeBinaryFile)
import qualified Data.ByteString.Char8 as Bs8
import Effectful.Concurrent.MVar.Strict (MVar, putMVar, newEmptyMVar, readMVar)
data Env es = Env {getInitialState :: Eff es Int}
injectEnv :: Subset xs es => Env xs -> Env es
injectEnv env = Env {getInitialState = inject env.getInitialState}
main :: IO ()
main = do
let env :: Env '[IOE] = Env {getInitialState = pure 0}
startServer (injectEnv env)
& runConcurrent
& runEff
startServer :: (Concurrent :> es, IOE :> es) => Env es -> Eff es ()
startServer env = do
stateMVar <- newEmptyMVar
getInitialStateWriteState (injectEnv env) stateMVar & runFileSystem
-- ^ compile error here
runServer stateMVar
getInitialStateWriteState :: (FileSystem :> es, Concurrent :> es) => Env es -> MVar Int -> Eff es ()
getInitialStateWriteState Env{getInitialState} stateMVar = do
state <- getInitialState
putMVar stateMVar state
writeBinaryFile "state.txt" (Bs8.pack $ show state)
runServer :: (Concurrent :> es, IOE :> es) => MVar Int -> Eff es ()
runServer stateMVar = do
state <- readMVar stateMVar
liftIO $ print state |
Beta Was this translation helpful? Give feedback.
You could create an
inject
equivalent for yourEnv
type, like this:And then you don't need to use
Subset
elsewhere. This compiles for me: