I've released a package candidate integrating katip with effectful

https://hackage.haskell.org/package/katip-effectful-0.0.1/candidate
i would love feedback, regarding scribes would it be preferrable for me to export the escape hatch i’ve used to remove the IOE constraints or to include scribes from other katip packages? the problem with the second approach is that i do not want to maintain multiple packages, so i would either increase the number of dependencies or include the scribes in sublibraries.

4 Likes

Thanks for making a wrapper library!

would it be preferrable for me to export the escape hatch i’ve used to remove the IOE constraints

The escape hatch looks clever, but if you call unliftStrategy within unsafeEmbedIOE, you’ll get a segmentation fault, so no :stuck_out_tongue:

I understand the motivation behind this to eliminate MonadIO/IOE constraints from logging functions (which would be unnecessary if katip’s classes were designed better, compare with log-base which gets it right and in turn log-effectful is very small), but if you choose to keep the helper, you need tight control over what actions are passed to it.

EDIT: Also, you could try pinging maintainers about Try removing MonadIO superclass by MichaelXavier · Pull Request #119 · Soostone/katip · GitHub. If they merge it, you at least won’t need to overwrite class methods.

1 Like

thanks for the reply, the mentioned PR is interesting.
Regarding unsafeEmbedIOE i guess it was the right choice to not export it, though it is surprising for me that calling unliftStrategy causes a crash, my intuition was that what would crash if anything would be useDict as ghc would not be able to prove the constraint, i guess my unsafeCoerce violates some invariant of getStaticRep? does withRunInIO use unliftStrategy:sweat_smile:? i guess that if my library break unlifts i will need a new hack.

does withRunInIO use unliftStrategy :sweat_smile:?

Yeah.

i guess my unsafeCoerce violates some invariant of getStaticRep?

The problem is not related to effectful, it’s more general. You have unsafeCoerce (MkDict @(KatipE :> es)) :: Dict (KatipE :> es, IOE :> es), so you have a dictionary of KatipE :> es (an Int internally) and you pretend that you have dictionaries for (KatipE :> es, IOE :> es) (two IntS). unliftStrategy simply tries to use the underlying Int of IOE :> es, but it’s not there so it accesses “something” and a segfault ensues.

After giving it more thought it seems to me that the current situation in which dictionary for KatipE :> es can still be properly accessed after the coerce is a coincidental consequence of what the code gets compiled into and you should not rely on it. Not 100% sure though.