Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapter for effectful effects library #162

Merged
merged 11 commits into from
Feb 1, 2023
Merged

Conversation

istathar
Copy link
Member

We have found ourselves in a situation where we want to use the Program monad from within a codebase that has been infested with the Eff effect system from the effectful package. This branch introduces a new ProgramE effect that allows lifting and unlifting from Eff es to Program.

@istathar istathar added the experimental Experiment or work-in-progress. Not necessarily intended for merging label Jan 30, 2023
@istathar istathar self-assigned this Jan 30, 2023
@istathar
Copy link
Member Author

Thanks again to @guaraqe's help yesterday, this is looking good. I'm going to add some Haddock documentation based on the example EffectSnippet.hs that we worked though and then this will be good!

Rename `runProgram` to `withProgram'`, paralleling the main
`withProgram`. Update the comments so the comparison between the two is
clear.
@istathar istathar added the core-effect Issues involving wrappers around effect systems label Jan 31, 2023
@istathar istathar marked this pull request as ready for review January 31, 2023 03:23
@istathar
Copy link
Member Author

One problem I can think of is that the Context that is current right before the inner Eff is run is possibly not the same as that that was stored when we fist invoked runProgramE. So we need a way to update (?) the Context that's stored in the effect before returning to the effect system.

@guaraqe
Copy link
Contributor

guaraqe commented Jan 31, 2023

Thanks for putting my name there!

Do you have an example of this... context changing between layers?

@istathar
Copy link
Member Author

You're right, I'll need to make an example that shows the problem.

@istathar
Copy link
Member Author

istathar commented Feb 1, 2023

The best I can do is something like this:

01:06:18Z (00.002) Begin trace
01:06:18Z (00.002) trace = 1104168dfdd8f371513f286b3545024a
01:06:18Z (00.002) Enter program2
01:06:18Z (00.002) span = 9ae1768dfdd8f87c
01:06:18Z (00.002) parent = 
01:06:18Z (00.002) Enter retrieveProgramName
01:06:18Z (00.002) span = 3d2e768dfdd8c35d
01:06:18Z (00.002) parent = 9ae1768dfdd8f87c
01:06:18Z (00.002) In Program
01:06:18Z (00.002) Enter (inner effect invocation)
01:06:18Z (00.002) span = ae67868dfdd808fa
01:06:18Z (00.002) parent = 3d2e768dfdd8c35d
01:06:18Z (00.002) Running effects
01:06:18Z (00.002) Enter nested ProgramE
01:06:18Z (00.002) span = 3aa2968dfdd89240
01:06:18Z (00.002) parent = 9ae1768dfdd8f87c
01:06:18Z (00.002) Inside inner Program
01:06:18Z (00.002) Leave nested ProgramE
01:06:18Z (00.002) Finished effects
01:06:18Z (00.002) Leave (inner effect invocation)
01:06:18Z (00.000) Sent 1 event
01:06:18Z (00.000) Sent 1 event
01:06:18Z (00.002) path = ()
01:06:18Z (00.002) Leave retrieveProgramName
01:06:18Z (00.000) Sent 1 event
01:06:18Z (00.002) Leave program2
01:06:18Z (00.000) Sent 1 event

which doesn't really help, other than to note that the parent inside nested ProgramE is wrong (it says 9ae1768dfdd8f87c but should be ae67868dfdd808fa)

I have an idea of what to do about this; I'll have a go. If I get stuck I'll post the code that generated the above.

@istathar
Copy link
Member Author

istathar commented Feb 1, 2023

Sorted it out with putStaticRep:

withProgram action = do
    -- extract Context τ
    ProgramE context1 <- Effect.getStaticRep

    -- lift to IO, using the provided specialized function which gives an unlift
    -- function for later use.
    Effect.withEffToIO $ \runInIO ->
        -- now in IO. Lift to Program τ
        subProgram context1 $ do
            -- now in Program τ. We form the function that will run an effect
            -- in Program τ, and pass it to the supplied action.
            action $ \inner -> do
                context2 <- getContext
                liftIO $ do
                    -- now in IO
                    runInIO $ do
                        -- now in (IOE :> es, ProgramE :> es) => Eff es, but
                        -- we need to update the Context τ in the ProgramE τ
                        -- effect with the one that was present just before we
                        -- ran the unlifting function.
                        Effect.putStaticRep (ProgramE context2)

                        -- now we can proceed with running the nested effects.
                        inner

I verified all this by inspection of the --debug=internal output from a crazy example that had was hacked to have a Program > Eff > Program > Eff > Program nesting, but for completeness, here's a trace in Honeycomb.

image

@istathar istathar merged commit 21da6fa into aesiniath:main Feb 1, 2023
@istathar istathar deleted the effectful branch February 1, 2023 05:07
@guaraqe
Copy link
Contributor

guaraqe commented Feb 2, 2023

Nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core-effect Issues involving wrappers around effect systems experimental Experiment or work-in-progress. Not necessarily intended for merging
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants