Difference between revisions of "Meet Bob The Monadic Lover"
m |
m (trying to make my english readeble... I didn't say understandable, did I?) |
||
Line 4: | Line 4: | ||
− | + | So, this is what I have in mind: suppose we have a friend who does very |
|
− | well with females/males. A lot of dating and so |
+ | well with females/males. A lot of dating and so... |
Now, we would like to keep track of all his/her ... ehm, affairs... |
Now, we would like to keep track of all his/her ... ehm, affairs... |
||
− | + | Let's create a type for that: we'll call it "Lover", and a "Lover" will be its constructor. |
|
− | be Lover. |
||
− | + | There it is: |
|
<haskell> |
<haskell> |
||
Line 22: | Line 21: | ||
Very very simple: it is a type where we can store the name of our |
Very very simple: it is a type where we can store the name of our |
||
+ | friend's beloveds. |
||
⚫ | |||
⚫ | |||
⚫ | |||
+ | |||
⚫ | |||
+ | going to need: |
||
<haskell> |
<haskell> |
||
> createLover name times = Lover (name,times) |
> createLover name times = Lover (name,times) |
||
− | > |
+ | > startAffairWith name (Lover (names,times)) = Lover (name,0) |
</haskell> |
</haskell> |
||
Line 37: | Line 39: | ||
Very simple: createLover takes a name of a beloved and the number of |
Very simple: createLover takes a name of a beloved and the number of |
||
− | ... dates. |
+ | ... let's call them "dates". |
− | The other function, |
+ | The other function, startAffairWith, takes the beloved's name and a |
− | + | lover. It will then substitute the lover's past beloved names with the |
|
− | beloved's one and remove every track of Bob's previous activities. |
+ | new beloved's one and remove every track of Bob's previous activities. |
− | Yes, you can say |
+ | Yes, you can say that: she's a very jealous tupe of chick and hates |
+ | Bob's past, as you can imagine... Let's face it, Bob is not a saint, |
||
− | imagine... |
||
+ | after all. |
||
− | + | If you want you can visualize "startAffairWith" with the name of the |
|
− | starting a relationship with: |
+ | person you are starting a relationship with: |
<haskell> |
<haskell> |
||
− | > jenny = |
+ | > jenny = startAffairWith "Jenny " |
− | > luisa = |
+ | > luisa = startAffairWith "Luisa " |
− | > antonia = |
+ | > antonia = startAffairWith "Antonia " |
</haskell> |
</haskell> |
||
− | + | As you may see, jenny, luisa and antonia are just partial |
|
+ | applications. They need a lover! Well, we know this kind of types, |
||
+ | don't we? |
||
+ | |||
+ | Be honest. With yourself, at least! |
||
+ | |||
+ | Now we need to create our lover. So, let's do it the right way. |
||
− | + | I'd like to introduce you my friend Bob: |
|
<haskell> |
<haskell> |
||
Line 82: | Line 91: | ||
Obviously when you start an affair you do not just meet once, without |
Obviously when you start an affair you do not just meet once, without |
||
− | doing anything... |
+ | doing anything... Well, perhaps the first date you just be quit, but |
+ | in the end... |
||
⚫ | |||
+ | What I mean is that Bob is quite proud of his past record and would |
||
⚫ | |||
⚫ | |||
− | lover, this is the first time! |
||
⚫ | |||
⚫ | |||
+ | for a lover" chicks, well, he has to pretend it is his first time! |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
+ | |||
⚫ | |||
<haskell> |
<haskell> |
||
Line 100: | Line 112: | ||
</haskell> |
</haskell> |
||
− | oneMoreTime does what it says: |
+ | oneMoreTime does what it says, and doues it well: adds one more time in |
+ | Bob's personal diary. |
||
− | Let's |
+ | Let's see: |
*Main> oneMoreTime bob |
*Main> oneMoreTime bob |
||
Line 116: | Line 129: | ||
the "Real Love", if you know what I mean. |
the "Real Love", if you know what I mean. |
||
− | + | Indeed he needs one more method: |
|
<haskell> |
<haskell> |
||
Line 125: | Line 138: | ||
changeBeloved is very simple: takes a name of a new beloved and |
changeBeloved is very simple: takes a name of a new beloved and |
||
− | concatenate with the names stored in Bob's loverDiary. Bob is proud |
+ | concatenate it with the names stored in Bob's loverDiary. Bob is proud |
− | of his |
+ | of his diary, and does not pretend to be a freshman every time he |
− | starts a new |
+ | starts a new relationship. |
− | What kind of a type |
+ | What kind of a type this Bob is! |
− | Let's test how our Bob is doing. Remember that he started with Paula |
+ | Let's test how our Bob is doing. Remember that he started with Paula |
+ | and 5 times in his record, that is not a bad start compared to mine: |
||
*Main> oneMoreTime $ oneMoreTime (luisa bob) |
*Main> oneMoreTime $ oneMoreTime (luisa bob) |
||
Line 143: | Line 157: | ||
*Main> |
*Main> |
||
− | + | Bob's doing quite fine, I'd say, if you like this kind of types. |
|
− | + | Now you can alse see Bob's different approaching techniques: "(antonia |
|
− | forget about Paula, while (changeBeloved "Carla " |
+ | bob)" will make Bob forget about Paula, while "(changeBeloved "Carla " |
+ | bob)" will not. |
||
− | I'm sure you know what method Bob likes most. |
+ | I'm sure you know what method Bob likes most. |
⚫ | |||
+ | Bob is that kind of types who just likes to increase the number of |
||
⚫ | |||
+ | "pieces" in their collection. Their lovers, indeed, are just "pieces". |
||
+ | |||
⚫ | |||
+ | confess. Luckily I'm not Bob and my beloved seems to appreciate this |
||
+ | fact, especially when Bob comes over with a couple of those stupid |
||
+ | gorgeous looking chicks. She keeps keeping an eye on me. She doesn't |
||
+ | trust me and probably thinks that inside myself there must be some |
||
+ | kind of a type like the type of Bob. |
||
+ | |||
+ | Sometimes I even start to believe that she could be right... But now |
||
+ | we are talking about Bob, a much more interesting chap the me. |
||
+ | |||
⚫ | |||
methods has to chain affairs without letting those ladies erase our |
methods has to chain affairs without letting those ladies erase our |
||
− | memory! It's just a matter of " |
+ | memory! It's just a matter of "lover's self-determination"! |
− | I hate writing |
+ | I hate writing these things, but... let's face reality! |
So, there's the (typically masculine) method: |
So, there's the (typically masculine) method: |
||
Line 168: | Line 195: | ||
together: the new lady (++) with the old ones, and newtimes + oldtimes! |
together: the new lady (++) with the old ones, and newtimes + oldtimes! |
||
− | That's all |
+ | That's all Bob wants! And needs! |
Let's see if it works: |
Let's see if it works: |
||
Line 182: | Line 209: | ||
Now, this is fine, sure. It fits Bob's needs. Still we would like to |
Now, this is fine, sure. It fits Bob's needs. Still we would like to |
||
− | have some way of |
+ | have some way of counting how many times an affairs resulted in a ... |
− | well, |
+ | well, I'm sure you know what I mean. |
− | I'd like to take a quite general solution, because Bob is lazy and |
+ | I'd like to take a quite general solution here, because our Bob is quite a lazy guy and |
− | sometimes forgets to update his diary. |
+ | sometimes, often,he forgets to update his diary, especially those nights he drunk too much. He is not an heavy drinker, far from it, but sometimes... |
+ | |||
− | write that the number of |
+ | So we would like to be able to write that the number of times ... |
+ | doubled. Hard to believe, but you never know with types like Bob: |
||
<haskell> |
<haskell> |
||
Line 201: | Line 230: | ||
*Main> |
*Main> |
||
− | So: Bob started at 5 with Paula, doubled it |
+ | So: Bob started at 5 with Paula, doubled it when changed Paula for |
+ | Carla (let me tell you: a good change!). Then he met Antonia, (the |
||
− | + | real love?) and told her he never did anything bad in his past (I was |
|
− | bad. We Antonia he did it 3 times. |
||
+ | there and could not refrain from laughing). With Antonia he did it 3 |
||
+ | times. Or so he pretends. But I know Antonia and this is probably |
||
+ | true. Anyway, never trust what Bob says, ever! |
||
Remember: when an affair is started by a beloved, like "(antonia bob)", |
Remember: when an affair is started by a beloved, like "(antonia bob)", |
||
− | we can only use "+", since |
+ | we can only use "+", since Antonia pretends Bob to be a freshman! |
*Main> chainAffairs (times (+3) (antonia bob)) (times (*2) (luisa bob)) |
*Main> chainAffairs (times (+3) (antonia bob)) (times (*2) (luisa bob)) |
||
Line 218: | Line 250: | ||
*Main> |
*Main> |
||
− | I'll ask it again: what kind of a type is this Bob |
+ | I'll ask it again: what kind of a type is this Bob??? A sex-intercourses calculating machine! |
− | intercourses calculating machine! |
||
There's a name for males who just collect ... well ... females: we |
There's a name for males who just collect ... well ... females: we |
||
call them Macho Men! |
call them Macho Men! |
||
− | Like Bob they just chain love affairs, doing just calculations: |
+ | Like Bob they just chain love affairs, doing just pure calculations: |
<haskell> |
<haskell> |
||
Line 239: | Line 270: | ||
> instance Macho Lover where |
> instance Macho Lover where |
||
− | > chain |
+ | > chain mychicks = chainAffairs mychicks |
</haskell> |
</haskell> |
||
− | Do you really |
+ | Do you really need some evidences?? |
There you are: |
There you are: |
||
Line 251: | Line 282: | ||
*Main> |
*Main> |
||
− | Look at the way Bob performs his |
+ | Look at the way Bob performs his calculations. He is basically mapping |
− | + | his diary with some function. And indeed this is what "times" is |
|
+ | supposed to do. |
||
"times" is just a "map" for Bob's loverDiary. |
"times" is just a "map" for Bob's loverDiary. |
||
− | In Haskell |
+ | In Haskell we have a class for this kind of types. I mean, those types |
− | that can be mapped as Bob's loverDiary can. |
+ | who map objects that can be mapped over as Bob's loverDiary can. |
+ | I think the name of their class i quite appropriate: they are called |
||
− | + | Functors. Pure calculating machine, without any soul left. |
|
− | + | Bob must be an instance of this class, you can be sure of that: |
|
<haskell> |
<haskell> |
||
Line 294: | Line 327: | ||
</haskell> |
</haskell> |
||
+ | |||
*Main> askLover (tellMyself 10) (tellLover 1) |
*Main> askLover (tellMyself 10) (tellLover 1) |
||
Line 303: | Line 337: | ||
*Main> askLover bob (tellLover 10) |
*Main> askLover bob (tellLover 10) |
||
Lover {loverDiary = ("Paula ",15)} |
Lover {loverDiary = ("Paula ",15)} |
||
+ | *Main> |
||
+ | |||
+ | bob last night |
||
+ | *Main> fmap (*3) chain bob (askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia" (antonia bob)))) (tellLover 10)) |
||
+ | Lover {loverDiary = ("Paula Antonia ClaudiaBerta Jennyfer L. ",45)} |
||
+ | *Main> |
||
+ | *Main> fmap (*3) $ askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia" (antonia bob)))) (tellLover 10) |
||
+ | Lover {loverDiary = ("Antonia ClaudiaBerta Jennyfer L. ",30)} |
||
+ | *Main> |
||
+ | *Main> chain bob $ fmap (*5) (askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia" (antonia bob)))) (tellLover 10)) |
||
+ | Lover {loverDiary = ("Paula Antonia ClaudiaBerta Jennyfer L. ",55)} |
||
*Main> |
*Main> |
||
Line 311: | Line 356: | ||
> m >>= f = askLover m f |
> m >>= f = askLover m f |
||
− | > |
+ | > whoLovedBy bob = do newLove "Lorenza " |
− | > lorenza <- tellMyself 3 |
+ | > lorenza <- tellMyself 3 |
− | > newLove "Antony " |
+ | > newLove "Antony " |
− | > antony <- tellMyself 6 |
+ | > antony <- tellMyself 6 |
− | > newLove "Luise " |
+ | > newLove "Luise " |
− | > luise <- tellMyself 2 |
+ | > luise <- tellMyself 2 |
− | > tellMyself (lorenza + antony + luise) |
+ | > tellMyself (lorenza + antony + luise) |
</haskell> |
</haskell> |
||
− | *Main> |
+ | *Main> whoLovedBy bob |
Lover {loverDiary = ("Lorenza Antony Luise ",11)} |
Lover {loverDiary = ("Lorenza Antony Luise ",11)} |
||
*Main> |
*Main> |
Revision as of 06:53, 3 September 2006
Meet Bob The Monadic Lover
Note: The source of this page can be used as a Literate Haskel file and can be run with ghci or hugs: so cut paste change and run (in emacs for instance) while reading it...
So, this is what I have in mind: suppose we have a friend who does very
well with females/males. A lot of dating and so...
Now, we would like to keep track of all his/her ... ehm, affairs...
Let's create a type for that: we'll call it "Lover", and a "Lover" will be its constructor.
There it is:
> newtype Lover a = Lover { loverDiary :: (Name,a) }
> deriving (Show)
> type Name = String
Very very simple: it is a type where we can store the name of our friend's beloveds.
Suppose our friend is a male. We will call him Bob.
Ok, we now start playing a bit. But first some useful functions we are going to need:
> createLover name times = Lover (name,times)
> startAffairWith name (Lover (names,times)) = Lover (name,0)
Indeed we need a way to create a lover, Bob, and start an affair with some beloved.
Very simple: createLover takes a name of a beloved and the number of ... let's call them "dates".
The other function, startAffairWith, takes the beloved's name and a lover. It will then substitute the lover's past beloved names with the new beloved's one and remove every track of Bob's previous activities.
Yes, you can say that: she's a very jealous tupe of chick and hates Bob's past, as you can imagine... Let's face it, Bob is not a saint, after all.
If you want you can visualize "startAffairWith" with the name of the person you are starting a relationship with:
> jenny = startAffairWith "Jenny "
> luisa = startAffairWith "Luisa "
> antonia = startAffairWith "Antonia "
As you may see, jenny, luisa and antonia are just partial applications. They need a lover! Well, we know this kind of types, don't we?
Be honest. With yourself, at least!
Now we need to create our lover. So, let's do it the right way.
I'd like to introduce you my friend Bob:
> bob = createLover "Paula " 5
Bob had a previous beloved: Paula. They dated 5 times...
Easy, isn't it?
So let's start playing around:
*Main> bob Lover {loverDiary = ("Paula ",5)} *Main> luisa bob Lover {loverDiary = ("Luisa ",0)} *Main> antonia bob Lover {loverDiary = ("Antonia ",0)} *Main>
Obviously when you start an affair you do not just meet once, without doing anything... Well, perhaps the first date you just be quit, but in the end...
What I mean is that Bob is quite proud of his past record and would like to see the 5 increased! I can understand him.
Instead everytime he starts a new affair with those "always looking for a lover" chicks, well, he has to pretend it is his first time!
Not what he wants, really.
Quite human, I'd say. Still, he has to.
Why don't we just give Bob a new method to ... well, you know...
> oneMoreTime (Lover (name,times)) = Lover (name,times + 1)
oneMoreTime does what it says, and doues it well: adds one more time in Bob's personal diary.
Let's see:
*Main> oneMoreTime bob Lover {loverDiary = ("Paula ",6)} *Main> oneMoreTime (antonia bob) Lover {loverDiary = ("Antonia ",1)} *Main>
Fine, it works as expected.
Now, Bob is, well, that kind of type that seems not really believe in the "Real Love", if you know what I mean.
Indeed he needs one more method:
> changeBeloved newname (Lover (name,times)) = Lover (name ++ newname,times)
changeBeloved is very simple: takes a name of a new beloved and concatenate it with the names stored in Bob's loverDiary. Bob is proud of his diary, and does not pretend to be a freshman every time he starts a new relationship.
What kind of a type this Bob is!
Let's test how our Bob is doing. Remember that he started with Paula and 5 times in his record, that is not a bad start compared to mine:
*Main> oneMoreTime $ oneMoreTime (luisa bob) Lover {loverDiary = ("Luisa ",2)} *Main> oneMoreTime $ oneMoreTime bob Lover {loverDiary = ("Paula ",2)} *Main> oneMoreTime $ oneMoreTime $ oneMoreTime $ oneMoreTime (antonia bob) Lover {loverDiary = ("Antonia ",4)} *Main> oneMoreTime $ oneMoreTime $ oneMoreTime $ changeBeloved "Carla " bob Lover {loverDiary = ("Paula Carla ",8)} *Main>
Bob's doing quite fine, I'd say, if you like this kind of types.
Now you can alse see Bob's different approaching techniques: "(antonia bob)" will make Bob forget about Paula, while "(changeBeloved "Carla " bob)" will not.
I'm sure you know what method Bob likes most.
Bob is that kind of types who just likes to increase the number of "pieces" in their collection. Their lovers, indeed, are just "pieces".
I mena, if I were to be Bob, well, I would agree with him, I must confess. Luckily I'm not Bob and my beloved seems to appreciate this fact, especially when Bob comes over with a couple of those stupid gorgeous looking chicks. She keeps keeping an eye on me. She doesn't trust me and probably thinks that inside myself there must be some kind of a type like the type of Bob.
Sometimes I even start to believe that she could be right... But now we are talking about Bob, a much more interesting chap the me.
Anyway we need a new method, for those kind of types like Bob. This methods has to chain affairs without letting those ladies erase our memory! It's just a matter of "lover's self-determination"!
I hate writing these things, but... let's face reality!
So, there's the (typically masculine) method:
> chainAffairs (Lover (names,oldtimes)) (Lover (newlady,newtimes)) = Lover (newlady++names,newtimes+oldtimes)
This method is very simple: it takes two love affairs, the old one and the new one, and chains them together: the new lady (++) with the old ones, and newtimes + oldtimes!
That's all Bob wants! And needs!
Let's see if it works:
*Main> chainAffairs (oneMoreTime $ oneMoreTime (antonia bob)) ( oneMoreTime $ changeBeloved "Carla " bob) Lover {loverDiary = ("Antonia Paula Carla ",8)}
Remember where Bob was starting from:
*Main> bob Lover {loverDiary = ("Paula ",5)} *Main>
Now, this is fine, sure. It fits Bob's needs. Still we would like to have some way of counting how many times an affairs resulted in a ... well, I'm sure you know what I mean.
I'd like to take a quite general solution here, because our Bob is quite a lazy guy and sometimes, often,he forgets to update his diary, especially those nights he drunk too much. He is not an heavy drinker, far from it, but sometimes...
So we would like to be able to write that the number of times ... doubled. Hard to believe, but you never know with types like Bob:
> times f (Lover (name,times)) = Lover (name, f times)
Let's see how this function works:
*Main> chainAffairs (times (+3) (antonia bob)) (times (*2) $ changeBeloved "Carla " bob) Lover {loverDiary = ("Paula Carla Antonia ",13)} *Main>
So: Bob started at 5 with Paula, doubled it when changed Paula for Carla (let me tell you: a good change!). Then he met Antonia, (the real love?) and told her he never did anything bad in his past (I was there and could not refrain from laughing). With Antonia he did it 3 times. Or so he pretends. But I know Antonia and this is probably true. Anyway, never trust what Bob says, ever!
Remember: when an affair is started by a beloved, like "(antonia bob)", we can only use "+", since Antonia pretends Bob to be a freshman!
*Main> chainAffairs (times (+3) (antonia bob)) (times (*2) (luisa bob)) Lover {loverDiary = ("Luisa Antonia ",3)} *Main>
instead:
*Main> chainAffairs (times (+3) (antonia bob)) (times (+2) (luisa bob)) Lover {loverDiary = ("Luisa Antonia ",5)} *Main>
I'll ask it again: what kind of a type is this Bob??? A sex-intercourses calculating machine!
There's a name for males who just collect ... well ... females: we call them Macho Men!
Like Bob they just chain love affairs, doing just pure calculations:
> class Macho f where
> chain :: (Num a) => f a -> f a -> f a
It is plain obvious that a lover of the kind of Bob must be an instance of this class:
> instance Macho Lover where
> chain mychicks = chainAffairs mychicks
Do you really need some evidences??
There you are:
*Main> chain (times (+3) (antonia bob)) (chain (times (*2) (changeBeloved "Carla " bob)) (times (+2) (luisa bob))) Lover {loverDiary = ("Antonia Paula Carla Luisa ",15)} *Main>
Look at the way Bob performs his calculations. He is basically mapping his diary with some function. And indeed this is what "times" is supposed to do.
"times" is just a "map" for Bob's loverDiary.
In Haskell we have a class for this kind of types. I mean, those types who map objects that can be mapped over as Bob's loverDiary can.
I think the name of their class i quite appropriate: they are called Functors. Pure calculating machine, without any soul left.
Bob must be an instance of this class, you can be sure of that:
> instance Functor Lover where
> fmap f = times f
Do you still want some evidence?
*Main> chain (fmap (+3) (antonia bob)) (chain (fmap (*2) (changeBeloved "Carla " bob)) (fmap (+2) (luisa bob))) Lover {loverDiary = ("Antonia Paula Carla Luisa ",15)} *Main>
to be continued
Bob's conscience asking...
> askLover lover answer = Lover (oldnames ++ newname,newtimes)
> where (oldnames,oldtimes) = loverDiary lover
> (newname,newtimes) = loverDiary (answer oldtimes)
> tellLover newtimes oldtimes = Lover ("", newtimes+oldtimes)
> tellMyself newtimes = Lover ("", newtimes)
> newLove love = Lover (love,0)
*Main> askLover (tellMyself 10) (tellLover 1) Lover {loverDiary = ("",11)} -- Leibniz *Main> askLover (newLove "Lory ") (tellLover 1) Lover {loverDiary = ("Lory ",1)} *Main> chain (bob) (chain (askLover (newLove "Cris ") (tellLover 2)) (askLover (antonia bob) (tellLover 4))) Lover {loverDiary = ("Paula Cris Antonia ",11)} *Main> askLover bob (tellLover 10) Lover {loverDiary = ("Paula ",15)} *Main>
bob last night
*Main> fmap (*3) chain bob (askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia" (antonia bob)))) (tellLover 10)) Lover {loverDiary = ("Paula Antonia ClaudiaBerta Jennyfer L. ",45)} *Main> *Main> fmap (*3) $ askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia" (antonia bob)))) (tellLover 10) Lover {loverDiary = ("Antonia ClaudiaBerta Jennyfer L. ",30)} *Main> *Main> chain bob $ fmap (*5) (askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia" (antonia bob)))) (tellLover 10)) Lover {loverDiary = ("Paula Antonia ClaudiaBerta Jennyfer L. ",55)} *Main>
> instance Monad Lover where
> return a = tellMyself a
> m >>= f = askLover m f
> whoLovedBy bob = do newLove "Lorenza "
> lorenza <- tellMyself 3
> newLove "Antony "
> antony <- tellMyself 6
> newLove "Luise "
> luise <- tellMyself 2
> tellMyself (lorenza + antony + luise)
*Main> whoLovedBy bob Lover {loverDiary = ("Lorenza Antony Luise ",11)} *Main>