
Hi all: I am a newbie of haskell and I'm reading "All about Monadshttp://www.haskell.org/all_about_monads/html/" right now, I have some question about the example shows in Chapter 2, it says that following code is ugly mothersPaternalGrandfather :: Sheep -> Maybe Sheep mothersPaternalGrandfather s = case (mother s) of Nothing -> Nothing Just m -> case (father m) of Nothing -> Nothing Just gf -> father gf and after intruduce the comb function, it become more cleaner: -- comb is a combinator for sequencing operations that return Maybe comb :: Maybe a -> (a -> Maybe b) -> Maybe b comb Nothing _ = Nothing comb (Just x) f = f x -- now we can use `comb` to build complicated sequences mothersPaternalGrandfather :: Sheep -> Maybe Sheep mothersPaternalGrandfather s = (Just s) `comb` mother `comb` father `comb` father my question is, why not define the function father and mother as type of father::Maybe Sheep -> Maybe Sheep? this can also clean the code and it avoid the additional function comb further more, why we need a function => with type of => m a -> ( a -> m b ) -> mb? define some function with type m a -> m b can solve these problems too. Thanks and BR

El sáb, 18-09-2010 a las 00:48 +0800, ender escribió:
my question is, why not define the function father and mother as type of father::Maybe Sheep -> Maybe Sheep? this can also clean the code and it avoid the additional function comb
The composition of these functions would then be nice, yes. However, you would have to duplicate the ugly handling of Nothings in each of the functions father, mother, sister, brother, etc.: father Nothing = Nothing father (Just x) = ... And you would still need a function of type Sheep -> Maybe Sheep, to fill in the dots.
further more, why we need a function => with type of => m a -> ( a -> m b ) -> mb? define some function with type m a -> m b can solve these problems too.
Look at the the type m a -> (a -> m b) -> m b in a slightly different way, namely by flipping its arguments. You get: (a -> m b) -> (m a -> m b) i.e., it transforms a function of type a -> m b into one of type m a -> m b, which can then be composed by (.). Given that we want to be able to deal with function of type a -> m b, This is exactly what we want. The usually given type m a -> (a -> m b) -> m b is just a convention because of the closer correspondence to the do-notation. Jürgen

On 9/17/10 12:48 PM, ender wrote:
my question is, why not define the function father and mother as type of father::Maybe Sheep -> Maybe Sheep? this can also clean the code and it avoid the additional function comb
Do note that `comb` is giving you a natural way of creating those functions: flip comb :: (a -> Maybe a) -> (Maybe a -> Maybe a) Since we can define comb, every (a -> Maybe a) has an associated function of type (Maybe a -> Maybe a). And if we use comb, then that means we can use the function at either type, just pick whichever one is easier for us to use at the time. If we only ever defined (Maybe a -> Maybe a) functions then we'd need to use a combinator to go the other way... f :: a -> Maybe a g :: Maybe a -> Maybe a f = ... g = flip comb f -- or -- f = g . Just g = ... Whether we use (flip comb) or (. Just) doesn't really matter too much. The point is that we can go both ways. -- Live well, ~wren

Also keep in mind that "Maybe" is a sort of a toy example of the concept being developed. It is indeed useful as a monad in its own right, but certainly not a case where the "comb" function is absolutely essential, as wren demonstrated. There are stronger motivations for using the 'comb' approach in cases where the type in place of 'Maybe' is more complex, or even completely abstract so you can't match against its constructors directly. -- James On Sep 17, 2010, at 11:26 PM, wren ng thornton wrote:
On 9/17/10 12:48 PM, ender wrote:
my question is, why not define the function father and mother as type of father::Maybe Sheep -> Maybe Sheep? this can also clean the code and it avoid the additional function comb
Do note that `comb` is giving you a natural way of creating those functions:
flip comb :: (a -> Maybe a) -> (Maybe a -> Maybe a)
Since we can define comb, every (a -> Maybe a) has an associated function of type (Maybe a -> Maybe a). And if we use comb, then that means we can use the function at either type, just pick whichever one is easier for us to use at the time. If we only ever defined (Maybe a -> Maybe a) functions then we'd need to use a combinator to go the other way...
f :: a -> Maybe a g :: Maybe a -> Maybe a
f = ... g = flip comb f
-- or --
f = g . Just g = ...
Whether we use (flip comb) or (. Just) doesn't really matter too much. The point is that we can go both ways.
-- Live well, ~wren _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (4)
-
ender
-
James Andrew Cook
-
Jürgen Doser
-
wren ng thornton