mfix for a nested monad

Hi, I'm trying to implement mfix for a monad that is nested inside another monad. I came up with the following logic for how to implement this, but I suspect there are some things I'm missing. My conclusion is that I want interpret (MFix f) = mfix (interpret.f) Does this seem right? Has this situation been discussed somewhere? -BenRI P.S. Here's what I mean by the monad being nested in another monad. Let's say that the monad M2 has interpreter i2, with type i2 :: M2 a -> M1 a and then M1 is the other monad, and has interpreter i1: i1 :: M1a -> a I suppose that the nesting is really a nesting of interpreters. P.P.S. I came up with some equational reasoning for how to treat mfix in the i2 interpreter. (a) For some interpreters `i`, it makes sense to require i (mfix f) = let x = (i . f) x in x (b) I want the composition of interpreters (i1.i2) to act like (a) above: (i1 . i2) (mfix f) = let x = (i1 . i2 . f) x in x (c) Rearranging, and then substituting using (a): i1 (i2 (mfix f)) = let x = i1 . (i2 . f) x in x = i1 (mfix (i2 . f)) (d) Therefore, we could set i2 (mfix f) = mfix (i2 . f) I'm probably going to make a `data` declaration for M2 so I could actually write i2 (Mfix f) = mfix (i2 . f) -BenRI

Hi Benjamin, It's impossible to answer your question without precisely pinning down what you mean by an "embedding." For each monad it is defined for, mfix is required to satisfy three laws: Strictness, Purity, and Left-Shrinking. If you can show that your "embedded" definitions satisfy those, then yes; you do have a valid value-recursion operator. You can find a description of these laws in Chapter 2 of [1]. Since you haven't specified what properties your "embedding" has, it's not possible to say anything in isolation. More traditionally, adding "new" effects to old monads in Haskell is achieved by using monad transformers [2]. Perhaps that's what you have in mind? If that's the case, then Section 4.9 of [1] lays out how mfix from the base monad can be lifted through a monad transformer stack while preserving the properties. If you can cast your design in terms of MTL style transformers, this would be the way to go. And if you do use the MTL package, then you'll have your MonadFix instances for free, since the library already defines them via the usual instance mechanism. Cheers, -Levent. [1] http://leventerkok.github.io/papers/erkok-thesis.pdf [2] https://hackage.haskell.org/package/mtl On Thu, Oct 25, 2018 at 7:43 AM Benjamin Redelings < benjamin.redelings@gmail.com> wrote:
Hi,
I'm trying to implement mfix for a monad that is nested inside another monad. I came up with the following logic for how to implement this, but I suspect there are some things I'm missing. My conclusion is that I want
interpret (MFix f) = mfix (interpret.f)
Does this seem right? Has this situation been discussed somewhere?
-BenRI
P.S. Here's what I mean by the monad being nested in another monad. Let's say that the monad M2 has interpreter i2, with type
i2 :: M2 a -> M1 a
and then M1 is the other monad, and has interpreter i1:
i1 :: M1a -> a
I suppose that the nesting is really a nesting of interpreters.
P.P.S. I came up with some equational reasoning for how to treat mfix in the i2 interpreter.
(a) For some interpreters `i`, it makes sense to require
i (mfix f) = let x = (i . f) x in x
(b) I want the composition of interpreters (i1.i2) to act like (a) above:
(i1 . i2) (mfix f) = let x = (i1 . i2 . f) x in x
(c) Rearranging, and then substituting using (a):
i1 (i2 (mfix f)) = let x = i1 . (i2 . f) x in x = i1 (mfix (i2 . f))
(d) Therefore, we could set
i2 (mfix f) = mfix (i2 . f)
I'm probably going to make a `data` declaration for M2 so I could actually write
i2 (Mfix f) = mfix (i2 . f)
-BenRI
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (2)
-
Benjamin Redelings
-
Levent Erkok