I am converting a codebase to use polysemy, and have run into trouble converting my uses of the LFresh
typeclass from unbound-generics
. The two operations I need have signatures
avoid :: LFresh m => [AnyName] -> m a -> m a
lunbind :: (LFresh m, Alpha p, Alpha t) => Bind p t -> ((p, t) -> m c) -> m c
which are clearly higher-order. I want to create an effect corresponding to the LFresh
class, and run it via the LFreshM
monad provided by unbound-generics
. Here's what I have tried so far, making use of Final
since that seemed to get me father than Embed
(and I am fine with having LFreshM
always be the last thing in the effect stack):
import Polysemy
import Polysemy.Final
import qualified Unbound.Generics.LocallyNameless as U
data LFresh m a where
Avoid :: [U.AnyName] -> m a -> LFresh m a
LUnbind :: (U.Alpha p, U.Alpha t) => U.Bind p t -> ((p,t) -> m c) -> LFresh m c
makeSem ''LFresh
runLFresh :: Member (Final U.LFreshM) r => Sem (LFresh ': r) a -> Sem r a
runLFresh = interpretFinal @U.LFreshM $ \case
Avoid xs m -> do
m' <- runS m
pure (U.avoid xs m')
LUnbind b k -> do
k' <- bindS k
pure (U.lunbind b k')
However, the case for LUnbind
does not type check since k' :: f (p, t) -> U.LFreshM (f x)
but it is expecting something of type (p, t) -> U.LFreshM (f x)
as the second argument to U.lunbind
; note the extra f
in the type of k'
.
I have other vague thoughts but I will leave it there for now, happy to clarify further. Not even sure if I'm on the right track. Ultimately, my real goal is just to "get polysemy to work with LFresh
from unbound-generics
", so if there's a better, completely different way to accomplish that I'm happy to hear about it too.