Generalised raise? Union SubsetOf constraint? - Polysemy

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Alex Chapman

I've got an effect that needs a reference to Sem r, because it includes a streaming type. And when the stream is run within the program, the result is also in a Sem r. But r needs to include the effect itself, which includes r, so I have infinite recursion. So instead I have been putting Sem r1 inside the streaming type, where r1 is assumed to be a subset of r, just not including my r-referencing effect. But now I can't run my stream inside the program, because it runs in Sem r1, and the program runs in Sem r. To get around this, I have:

prog
  :: ( Members '[ {- most effects in here -} ] r1
      , r ~ (MyStreamingEffect (Sem r1) ': r1)
      )
  => foo -> bar -> Sem r ()
prog foo bar = do
   ...
  result <- raise $ useMyStreamingEffect foo bar
  ...

This is working for now, but I don't like that I have to use raise, and that MyStreamingEffect has to be on top of the stack. What I think might be better is a function a bit like a generalised raise, with a type like SubsetOf r1 r => Sem r1 a -> Sem r a. Is this possible? Does it already exist in some form?

TheMatten

How do you use it? Because normally that's what m in data SomeEffect m a is for

Alex Chapman

Well, I have a Codec effect, much like the Boomerang effect I describe here: https://funprog.zulipchat.com/#narrow/stream/216942-Polysemy/topic/Bundle.20example/near/197125529
I use this to decode a ByteString from a file into a stream of data, containing a SourceT (Sem r1) (HashMap FieldName Text), and then to re-encode this after manipulation. So the effect type is Codec ByteString (SourceT (Sem r1) (HashMap FieldName Text). Then I have a function that runs over the data in the stream, compiling a summary, with a type like Member (Error SomeError) r => SourceT (Sem r) (HashMap FieldName Text) -> Sem r Summary. I'll rewrite my above example with slightly less pseudocode:

prog
  :: ( Members
      '[ Error SomeError
       , File FilePath ByteString
       , Log
       , ...
       ] r1
     , r ~ (Codec ByteString (SourceT (Sem r1) (HashMap FieldName Text)))
  => FilePath -> Sem r ()
prog file =
  stream <- load file >>= decode
  summary <- raise $ compileSummary stream
  log ("Summary of '" % string % "': " % summary) file summary

compileSummary :: Member (Error SomeError) r => SourceT (Sem r) (HashMap FieldName Text) -> Sem r Summary
compileSummary = ...
Alex Chapman

And within compileSummary I call https://hackage.haskell.org/package/machines-0.7/docs/Data-Machine-Runner.html#v:foldMapT, which is what forces the Sem r in the return to be the same Sem r as in the SourceT.

TheMatten

Not sure if there's better way of doing this with current interface - maybe we could have a typeclass that encodes subset relation between rows to make this at least a little bit nicer. Or maybe you could take transformer separately as an argument of Codec, to be provided with m inside