[Agda] Indexed Monads
Dan Doel
dan.doel at gmail.com
Sun Feb 24 19:44:24 CET 2008
Hello,
I've been playing with Agda 2 in my spare time lately, and have found it quite
enjoyable (and rather remarkable; it's amazing how close to, say, Haskell one
can get in terms of the conciseness of function definitions). However, part
of the standard library has left be a bit confused, so I thought I'd ask
about it, if it's not too much trouble.
Specifically: indexed monads (and applicative functors, for that matter). I
hadn't seen them before, but was able to find some brief explanation online
describing them. However, unlike most of the articles I found, the indexed
monads in the standard library are indexed by values rather than types. Thus,
to get back to type-indexed monads, one must use a function (I -> Set), as in
the state monad included.
This, of course, works fine for the ordinary state monad, as one can choose
the unit type as the index set, and (\_ -> S) as the function, where S is the
type of state. However, one of the motivations for using indexed monads is a
state monad where the state type can change over the course of the
computation. But this requires an index type rich enough to represent all the
types the state can take on, and a corresponding function. The only way I
came up with to use the included indexed state monad was as follows:
natToType : ℕ -> Set
natToType 0 = ℕ
natToType 1 = Fin 1
natToType n = [ ℕ ]
test : {M : IFun ℕ}{i : ℕ}(SM : RawIMonadState natToType M)
-> M i 2 ⊤
test SM = put {_} {0} zero >> put {_} {1} fz >> put {_} {2} (zero ∷ [])
where
open RawIMonadState SM
Which, if you'll excuse my saying so, seems rather cumbersome. By contrast, I
fooled around to make type-indexed monads (the main change being 'IFun =
Set -> Set -> Set -> Set', and associated cleanup), and the code
corresponding to the above is:
test : {i : Set}{M : IFun}(SM : RawIMonadState M) -> M i [ ℕ ] ⊤
test SM = put zero >> put tt >> put (zero ∷ [])
where
open RawIMonadState SM
which works without any overhead (although I changed fz to tt, as unresolved
metas resulted from fz never being used and having no declared type).
I initially ran into the issue implementing a monad for delimited
continuations, the definition of which was straight forward enough, but the
use of which suffers from the same problem as the indexed state monad. And,
it appears to me that all monads that rely on type indices will be the same
way.
I can't, of course, claim that my type-indexed definition is perfect, either.
For instance, my RawMonad records arbitrarily set the index type to unit to
prevent problems with unresolved metas elsewhere. This means that the
ordinary state monad doesn't fit with that record, however, as for that, one
wants all indices to be of some fixed type S. This particular case turns out
not to be much of a problem, as the indexed state monad works just as well
(modulo the fz type issue mentioned above), but it would inhibit any other
monad that wants a single, particular index type (reader and writer come to
mind). Off the top of my head, a function : Set -> Set, like the above I ->
Set might be used to overcome this, but it's still not ideal.
Anyhow, to sum up, I was just wondering if there was some particular reason
for choosing value-indexed monads, or some way of using them in a less
cumbersome manner that I'm totally missing. I suppose I could see their use
in lieu of phantom types (phantom values?), but it seems like an odd choice
to me, given that the examples of indexed monads I found relied on the
indices being types.
Thanks very much for your time (and for Agda; it's very cool).
-- Dan Doel
P.S.: If desired, I could provide the source for the delimited continuation
monad. I attempted to stick as close as possible to the format in
Category.Monad.State. Though it's nothing particularly complex (shift and
reset with a single prompt), it's another motivator for having/example of
indexed monads.
More information about the Agda
mailing list