sayo-hs / heftia

higher-order effects done right for Haskell
Mozilla Public License 2.0
46 stars 1 forks source link

Please provide simple bracket example #14

Open tomjaguarpaw opened 1 week ago

tomjaguarpaw commented 1 week ago

I would like to understand how bracket works in heftia. I have got as far as the below, but I don't know how to run something that has a SendSig Resource in it. I feel this must require resourceToIO, but I don't see how I should use it. Can you help?

{-# LANGUAGE GHC2021 #-}

import Control.Applicative ((<|>))
import Control.Effect.ExtensibleChurch (runEff)
import Control.Effect.Interpreter.Heftia.NonDet (runNonDet, runChooseH)
import Control.Monad.IO.Class (liftIO, MonadIO)
import Data.Effect.Resource (bracket_, Resource)
import Control.Effect (SendSig)

example :: (MonadIO f, SendSig Resource f) => f Integer
example =
    bracket_
        (liftIO (putStrLn "Acquired"))
        (liftIO (putStrLn "Released"))
        ( do
              r <- pure 1
              liftIO (putStrLn "Used")
              pure r
          )
ymdryo commented 1 week ago

Ah, sorry about that. resourceToIO hasn't been implemented yet. For now, an interface similar to unliftio can be used with runUnliftIO and withRunInIO.

import Control.Effect (type (<<:))
import Control.Effect.Interpreter.Heftia.Unlift (runUnliftIO)
import Control.Exception (bracket_)
import Control.Monad.Freer.Church (FreerChurch)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Effect.Unlift (UnliftIO, withRunInIO)
import Data.Hefty.Extensible (ExtensibleUnion)

example :: (MonadIO f, UnliftIO <<: f) => f Integer -- `<<:` = `SendSig`
example =
    withRunInIO \run -> do
        bracket_
            (run $ liftIO (putStrLn "Acquired"))
            (run $ liftIO (putStrLn "Released"))
            ( run do
                r <- pure 1
                liftIO (putStrLn "Used")
                pure r
            )

main :: IO ()
main = do
    x <- runUnliftIO @FreerChurch @ExtensibleUnion example
    print x

I think it's possible to write resourceToIO using this method as well.

ymdryo commented 1 week ago

Note that: Since UnliftIO conflicts with continuation-based operations, you cannot use the usual runState or runThrow handlers; instead, you need to use IO-based handlers like runStateIORef or runThrowIO in this case. For more advanced content, please refer to: https://sayo-hs.github.io/heftia/2024/09/09/unliftio.html

At present, the usability of the UnliftIO effect is not very good. Currently, only these two IO-based handlers are implemented. (Additionally, as of the latest version 0.3.1 on Hackage, the type signature of runStateIORef is incorrect and lacks sufficient generalization.) I need to expand them further.