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

Nested mixed effects? #446

Open
eyeinsky opened this issue Jan 31, 2022 · 3 comments
Open

Nested mixed effects? #446

eyeinsky opened this issue Jan 31, 2022 · 3 comments

Comments

@eyeinsky
Copy link
Contributor

Is something like the following possible in polysemy where given the effects

data E1 :: Effect where
  E1_unit :: E1 m ()
  E1_rec :: something.. a -> E1 m a

makeSem ''E1

data E2 :: Effect where
  E2_unit :: E2 m ()
  E2_rec :: something.. a -> E2 m a

makeSem ''E2

one could write something like this:

main = do
  e1_rec $ do
    e1_unit
    e2_unit
    e2_rec $ do
      e1_unit
      e2_unit
  e1_rec $ do
    e1_unit
    e2_unit
  ..

I.e I arbitrarily mix different effects under both effects' _rec variants and the effect stack is same on each "level".

My actual use case is that I have DSLs for generating css and javascript both of which have their separate effects/GADTs and interpreters, and am wondering if I could re-use them without writing a sum GADT.

@googleson78
Copy link
Member

This works, for something.. = m. Am I misunderstanding your question?

{-# LANGUAGE TemplateHaskell #-}

module Bla where

import Polysemy

data E1 :: Effect where
  E1_unit :: E1 m ()
  E1_rec :: m a -> E1 m a

makeSem ''E1

data E2 :: Effect where
  E2_unit :: E2 m ()
  E2_rec :: m a -> E2 m a

makeSem ''E2

bla :: Member E1 r => Member E2 r => Sem r ()
bla = do
  e1_rec $ do
    e1_unit
    e2_unit
    e2_rec $ do
      e1_unit
      e2_unit
  e1_rec $ do
    e1_unit
    e2_unit

@googleson78
Copy link
Member

Of course, this doesn't restrict the do block to only contain E1 and E2 in it, which might be an issue for you?

@eyeinsky
Copy link
Contributor Author

eyeinsky commented Feb 1, 2022

@googleson78 thanks! I had briefly tried it, but backed out as I couldn't figure out how could I use the m in interpretation (also using interpretH, and just now getting it to work with pureT is scary..).

In the "hard part" below I'd essentially like to run all the effects to the end using the current state, but modify the writer before writing it in to the "main interpretation":

-- | E1 is meant to be interpreted to these effects:
type E1_Base = '[State Int, Writer String]

-- | Interpret E1 in terms of E1_Base
e1ToBase :: forall r . (Members E1_Base r) => InterpreterFor E1 r
e1ToBase = interpretH $ \case
  E1_unit -> do
    modify @Int (+1)
    tell @String "this"
    pureT ()
  E1_rec m -> do
    -- the hard part:
    -- state0 <- get @Int
    -- let
    --   (writer, (state1, a)) = runWriter $ runState state0 $ ..?.. $ m
    --   modifiedWriter = "begin " <> writer <> " end"
    -- put @Int state1
    -- tell @String modifiedWriter
    -- return a
    return undefined

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants