Rebindable syntax for monads and arrows
Greetings all, This message is a sort of a poll to find out how much interest the community has in an implementation of rebindable syntax for monads and arrows. You can send your answers directly to me (sabry ... indiana edu) and I will summarize to the list if appropriate. An example using monads ----------------------- The type Vec below is almost a monad: - the operations vreturn and @>>= are almost of the right type (they have an additional constraint FinSet a =>) - the operations vreturn and @>>= satisfy the monad laws class Eq a => FinSet a where enumerate :: [a] newtype Vec a = Vec (a -> Float) unV (Vec f) = f vreturn :: FinSet a => a -> Vec a vreturn a = Vec (\ b -> if a==b then 1 else 0) (@>>=) :: FinSet a => Vec a -> (a -> Vec b) -> Vec b (Vec va) @>>= f = Vec (\ b -> sum [ (va a) * (unV (f a) b) | a <- enumerate]) Because of the additional type constraint (FinSet a =>) we cannot make the type Vec an instance of the class Monad, and hence we cannot use the do-notation to express our computations. ----------------------------------------------------------------------------- Question I ----------------------------------------------------------------------------- Do you have other examples, where you wished you could define instances of the class Monad with operations whose types are more constrained than required? Or more generally do you feel that allowing such a behavior is worthwhile? ----------------------------------------------------------------------------- Question II ----------------------------------------------------------------------------- Arguably the do-notation for monadic computations is nice but the overhead of writing using explicit combinators is not that bad. The situation for arrows is quite different: the syntactic sugar for arrows is almost essential and it often expands into something you _do_not_want_to_write_ So, do you have examples, where you wished you could define instances of the class Arrow with operations whose types are more constrained than required? ----------------------------------------------------------------------------- Thanks for your feedback. Amr Sabry (based on discussions with Peter Gammie, Ross Patterson, Simon Peyton Jones, and Josef Svenningsson)
In article <200501071653.j07GrHMu002630@asterix.cs.indiana.edu>, Amr A Sabry <sabry@cs.indiana.edu> wrote:
The type Vec below is almost a monad: - the operations vreturn and @>>= are almost of the right type (they have an additional constraint FinSet a =>) - the operations vreturn and @>>= satisfy the monad laws
class Eq a => FinSet a where enumerate :: [a]
newtype Vec a = Vec (a -> Float) unV (Vec f) = f
vreturn :: FinSet a => a -> Vec a vreturn a = Vec (\ b -> if a==b then 1 else 0)
(@>>=) :: FinSet a => Vec a -> (a -> Vec b) -> Vec b (Vec va) @>>= f = Vec (\ b -> sum [ (va a) * (unV (f a) b) | a <- enumerate])
Because of the additional type constraint (FinSet a =>) we cannot make the type Vec an instance of the class Monad, and hence we cannot use the do-notation to express our computations.
You can to do this with GADTs: data MyVec a where MkMyVec :: (FinSet a) => Vec a -> MyVec a instance Monad MyVec where return a = MkMyVec (vreturn a) etc. GADTs are scheduled for version 6.4 of GHC. The version of GHC now in CVS does not currently allow this however, see GHC bug #1097046. -- Ashley Yakeley, Seattle WA
Ashley Yakeley wrote:
Amr A Sabry <sabry@cs.indiana.edu> wrote:
Because of the additional type constraint (FinSet a =>) we cannot make the type Vec an instance of the class Monad, and hence we cannot use the do-notation to express our computations.
You can to do this with GADTs:
data MyVec a where MkMyVec :: (FinSet a) => Vec a -> MyVec a
instance Monad MyVec where return a = MkMyVec (vreturn a) etc.
Bug #1097046 aside, I don't see how this can possibly work. There's nothing to prevent return from being passed an argument for which there's no FinSet instance. -- Ben
Ben Rudiak-Gould wrote:
Bug #1097046 aside, I don't see how this can possibly work. There's nothing to prevent return from being passed an argument for which there's no FinSet instance.
You're right, I guess it's not a monad after all, though you might be able to write the (>>=) function. -- Ashley Yakeley, Seattle WA
On 07 jan 2005, at 17:53, Amr A Sabry wrote:
Greetings all,
This message is a sort of a poll to find out how much interest the community has in an implementation of rebindable syntax for monads and arrows. You can send your answers directly to me (sabry ... indiana edu) and I will summarize to the list if appropriate.
An example using monads -----------------------
The type Vec below is almost a monad: - the operations vreturn and @>>= are almost of the right type (they have an additional constraint FinSet a =>) - the operations vreturn and @>>= satisfy the monad laws
class Eq a => FinSet a where enumerate :: [a]
newtype Vec a = Vec (a -> Float) unV (Vec f) = f
vreturn :: FinSet a => a -> Vec a vreturn a = Vec (\ b -> if a==b then 1 else 0)
(@>>=) :: FinSet a => Vec a -> (a -> Vec b) -> Vec b (Vec va) @>>= f = Vec (\ b -> sum [ (va a) * (unV (f a) b) | a <- enumerate])
Because of the additional type constraint (FinSet a =>) we cannot make the type Vec an instance of the class Monad, and hence we cannot use the do-notation to express our computations.
----------------------------------------------------------------------- ------ Question I ----------------------------------------------------------------------- ------
Do you have other examples, where you wished you could define instances of the class Monad with operations whose types are more constrained than required? Or more generally do you feel that allowing such a behavior is worthwhile?
A resounding yes to that one. Both of them. The example I have is one of trying to put numerical values under the identity monad and then record expressions on those values within the monad itself. This was somewhat hampered by the impossibility of putting additional type constraints on instances of Monad.
----------------------------------------------------------------------- ------ Question II ----------------------------------------------------------------------- ------
Arguably the do-notation for monadic computations is nice but the overhead of writing using explicit combinators is not that bad. The situation for arrows is quite different: the syntactic sugar for arrows is almost essential and it often expands into something you _do_not_want_to_write_
So, do you have examples, where you wished you could define instances of the class Arrow with operations whose types are more constrained than required?
Unfortunately not, but I must admit to not having played with Arrows. Might be a nicer idiom for what I'm doing though... Doei, Arthur. -- arthurvl@cs.uu.nl | Work like you don't need the money A friend is someone with whom | Love like you have never been hurt you can dare to be yourself | Dance like there's nobody watching
participants (4)
-
Amr A Sabry -
Arthur van Leeuwen -
Ashley Yakeley -
Ben Rudiak-Gould