Personal tools

Meet Bob The Monadic Lover

From HaskellWiki

Revision as of 15:56, 2 May 2010 by Kanak (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Meet Bob The Monadic Lover

Note: The source of this page can be used as a Literate Haskell 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 type of a chick and hates Bob's past, as you can imagine... But, let's face it, Bob is not a saint, after all, and I frankly understand her.

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 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'll just be quite, but in the end...

What I mean is that Bob is quite proud of his past record and would like to see that 5 increased, not erased! 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 does 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 a 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 ",7)}
 *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 also 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 like to increase the number of "pieces" in their collection. Their lovers, indeed, are just "pieces".

I mean, 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 than me.

Anyway we need a new method, for those kind of types like Bob. This method 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, without having to write "oneMoreTime" so many times. This is especially true with a kind of a type like our Bob, whose activity can be quite difficult to track.

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 a 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 sexual-intercourse 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 is 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> 

Well, is Bob just that? I mean, I know him and he can be the worst kind of a type, I'm totally aware of that. No doubt. But, you know, there are times when Bob and I hang together, and with me he's not just telling bull... you got it.

Sometimes I find him alone in his huge, empty apartment down town, staring at the full moon and almost crying in despair... Sometimes he opens up with me, and starts telling me whom he really loved. You won't believe it, I'm sure, but once he said that Paula didn't count anything in his life. I've said it all!

Now, I'm sure that when he's alone, Bob talks with himself about himself. He's not just a Macho Functor who sums up story after story as a calculating machine. He judges his love, I doesn't say "I changed my beloved" or stuff like that. I'm sure he's able to love. Sometimes.

I'd like to be there when Bob talks with his soul. I'd like to hear the soul asking Bob about his lovers. And I'd like to see if in these occasions Bob uses the same methods, with himself.

I'm sure you know what I mean. You too have a soul you talk with. And you know that your soul knows it all. You don't need to talk with her as you would with me. She knows part of your answers, because you two guys, whether you want it or not, share the same past, the same memories. This is you, after all. And you know better then I do. Am I right?

I don't want to start doing philosophy. This is not the place. But you must agree that it would be unjust to believe that Bob is just a Macho Functor. You must concede that Bob is something more. He is a soul talking with Bob's self... Call it ego, call it psyche, call it as you want, but you perfectly know what we are talking about. Do not lie to yourself!

Ahh, who was that philosopher that said that lying to others is the exception. The rule is lying to ourselves. Friedrich what? I don't remember anymore...

Ok, let's stop with all this bull... ops, I start talking like Bob!

Let's go on and see how we can express this human behavior that Bob seems to have, sometimes.

We said that the soul asks Bob, but that the soul knows part of the answer. So the answer must imply something the soul knows. In other word, the answer must be some kind of partial application, right?

So let's write this first:

> tellLover newtimes oldtimes = Lover ("", newtimes+oldtimes)

And now the question:

> askLover lover answer = Lover (oldnames ++ newname,newtimes)
>     where (oldnames,oldtimes) = loverDiary lover
>           (newname,newtimes) = loverDiary (answer oldtimes)

This seems to be just fine to me. "askLover" takes a partial answer and fills it with the missing part (oldtimes) in the where clause: the soul's memory, extracted from the loverDiary of the lover, memory that Bob and his soul share, is added to the partial answer.

But, we said, this is just what we see. When Bob's soul is alone with herself, I mean, inside Bob, who is probably sitting somewhere all stoned and drunk, this soul needs some methods to talk to herself about new loves and new times.

So, let's write these soul's methods:

> tellMyself newtimes = Lover ("", newtimes)
> newLove love = Lover (love,0)

To me that seems to be enough. Well, just give it a try:

 *Main> askLover (tellMyself 10) (tellLover 1)
 Lover {loverDiary = ("",11)}

Well, this for sure is not Bob! Look at this poor soul of a type. 11 dates and no names. Sounds suspicious to me... This guy, all alone, doing what??

I'd have a name for such a "spirit"! Remember that German philosopher who was talking of this stuff all alone, the essence... I don't remember his name but if you look up at the Wikipedia something could come up.

Let's try again:

 *Main> askLover (newLove "Lory ") (tellLover 1)
 Lover {loverDiary = ("Lory ",1)}

Well this is not Bob. I don't know him personally. But he doesn't seem such an interesting guy, judging from numbers (you know, the macho functor stuff).

So here's Bob:

 *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> 

Now I recognize him. The old dear Bob. What a type.

Be careful, with this stuff, though. Do not pretend it being the truth about Bob. When Bob tells something aloud to his soul you never know what he's talking about. Truth is not what Bob likes most.

You sure know that by now!

Just to show, this is Bob a couple of weeks ago. We went over to one of his friends, and he started, as usual, talking about what kind of a type of a lover he is, showing off names I would not dare to write here.

Just a couple of examples:

 *Main> fmap (*3) chain bob  (askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia " (antonia bob)))) (tellLover 10))
 Lover {loverDiary = ("Paula Antonia Claudia Berta Jennyfer L. ",45)}
 *Main> fmap (*3) $ askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia " (antonia bob)))) (tellLover 10)
 Lover {loverDiary = ("Antonia Claudia Berta Jennyfer L. ",30)}
 *Main> chain bob $ fmap (*5) (askLover (changeBeloved "Jennyfer L. " (changeBeloved "Berta " (changeBeloved "Claudia " (antonia bob)))) (tellLover 10))
 Lover {loverDiary = ("Paula Antonia Claudia Berta Jennyfer L. ",55)}
 *Main> 

Would you believe it? Certainly I don't.

Why? Because I happen to know Bob better then you!

Well, all this soul stuff looks interesting. We could have some fun with it.

For sure now we can build female lovers who are not just ... partial applications.

Introducing Alessia:

 *Main> let alessia = askLover (newLove "Joseph ") (tellLover 4)
 *Main> alessia
 Lover {loverDiary = ("Joseph ",4)}
 *Main> 

And what about the bird of a new soul without any memory and experience.

Sorry, but I find English not expressive enough for what I mean. Well, I'll admit that it could be just me. But how do you guys say when someone is going to, you know, be born? As far as my English goes "born" is the past participle of "bear". This is fine, but I believe it's just the woman's perspective. She bears what is going to be born.

Ok, let's start from a pregnant woman. I must confess I do not have very much experience in this field, but I would probably express pregnancy this way:

 *Main> askLover (askLover (newLove "Bob ") (tellLover 0)) (tellLover 1)
 Lover {loverDiary = ("Bob ",1)}
 *Main> 

I don't know if it does make sense. But for sure pregnancy doesn't make any sense to Bob. So, possibly, this is the right way to express it. At least when talking about Bob.

But I need a name for this method: the act of the birth. We need a future participle, this is what we really need. You know, something like the Latin "naturum" (is to be born), the Greek physis, the Italian nascita or natura.

Yes, something like "nature" seems to be appropriate. But, just to keep it apart from the "real nature" (if such a thing exists), like wildness and stuff like that (Bob lives down town and hates everything that even seems "natural"), we will use the Greek term physis.

Also as an homage to that Greek philosopher, Eraclo, Heracloto, I don't remember, that used to say: "Physis kryptestai phylein" (nature loves to hide herself).

> physis = Lover ([],0)

Let's try it:

 *Main> let andrea = physis
 *Main> andrea
 Lover {loverDiary = ("",0)}
 *Main> 

Ok, seems to be working. And also the name seems appropriate. Before his birth, he was not. During the evaluation of his "going to be born" he became a "definitely born".

And how a Lover dies? This is simple:

 
 
> dies lover = Lover ([],0)
 *Main> let alessia = askLover (newLove "Joseph ") (tellLover 4)
 *Main> alessia
 Lover {loverDiary = ("Joseph ",4)}
 *Main> dies alessia
 Lover {loverDiary = ("",0)}
 *Main> 

Seems to work to me.

I know what you are going to say now. How can you tell who's just born from who's just died?

Be careful with this kind of arguments with me. I can be even more demanding. For instance, look at this guy:

 *Main> askLover (tellMyself 0) (tellLover 0)
 Lover {loverDiary = ("",0)}
 *Main> 

Can you tell me whether he is alive or dead?

If you cannot, you'd better start asking yourself a few questions.

If you can, I'm sure you are going to come up with something funny, like "This guy gotta be a priest!".

Anyway is far from being a lover, and a kind of a type like Bob would not spend a single second the have a conversation with him.

From our perspective, though, there are no differences at all. But for a Macho Functor Lover, well, being dead turns out to be a huge loss. Take it for granted!

I like playing this game, Haskell let us create quite interesting kinds of types. I was thinking, do you remember that guy in that movie?

How was titled? Memento I think.

This Leonard kind of a type, who, when falls asleep, looses all his short term memory... I'd like to introduce this kind of type.

I think this is going to be an easy type:

> newtype Leonard a = Leonard { leonardDiary :: (Name,a) }
>     deriving (Show)
 
> askLeonard lover answer = Leonard (oldnames,oldtimes)
>     where (oldnames,oldtimes) = leonardDiary lover
>           (newname,newtimes) = leonardDiary (answer oldtimes)
 
> leonard = Leonard ("Jorja Fox", 1000)
 
> tellLeonard newtimes oldtimes = Leonard ("", newtimes+oldtimes)
> tellLeonardSelf newtimes = Leonard ("", newtimes)
> newLeonardLove love = Leonard (love,0)

I believe this is him. Well, just try:

 *Main> askLeonard (leonard) (tellLeonard 100000000)
 Leonard {leonardDiary = ("Jorja Fox",1000)}
 *Main> 

Seems to be Leonard to me. Definitely.

What do you think, could this kind of a type be a Macho? I believe he can:

> instance Macho Leonard where
>     chain (Leonard (a,b)) (Leonard (c,d)) = (Leonard (a,b))

Sure he can. Look here:

 *Main> chain leonard (askLeonard (newLeonardLove "Angolie ") (tellLeonard 3))
 Leonard {leonardDiary = ("Jorja Fox",1000)}
 *Main> 

This is definitely the Leonard type.

Now I'm asking to myself if Leonard can also be considered a Functor.

Yes, I do believe he can:

> instance Functor Leonard where
>     fmap f (Leonard (a,b)) = Leonard (a,f b)

Try him:

 *Main> fmap (+6) (chain leonard (askLeonard (newLeonardLove "Angolie ") (tellLeonard 3)))
 Leonard {leonardDiary = ("Jorja Fox",1006)}
 *Main> 

A bit strange, isn't it? Seems like Leonard was thinking to do it with Jorja... Well, perhaps this is because he's awake. Just wait for him to go to sleep and check again when he wakes up. Otherwise, well, my fault!

Ohh gosh! I'm sure now you are starting to believe I'm going to build up a Matrix!

No, I'm not. We'd better go back to our Being John Malchowich style. Right?

Now we can say that Bob, after all, seems to have a soul. Great! The problem, now, is to find a suitable Haskell class for this kind of Lovers, who are not just Macho Functors.

It seems that Haskell developers were quite aware that this need could show up, and they created that class called Monad class.

I must tell you the truth: I don't know if I like that name. Anyway, sometimes I think it sounds good. In Italian "monade" sounds a bit like "modo", "mode" "modality", you know, that kind of sound. Sure I was told it comes from Greek and all that. But a name is first a sound. Only secondly a meaning. And what Monad means, well, we know: it's a kind of a type like our Bob. Seems just a Macho Functor, but has an inside ... side. This doing questions and doing answering going on.

So I could say I like the "monad" name, because its sound makes me remember the it could mean "a way of doing something". And I believe that we are, after all, just the way we do...

I like this "do" word too. In Italian we don't have something you can put everywhere and it always seems to fit in. It doesn't matter if it really doesn't. It seems it does.

So, when I think of a kind of a type like a "monad" I always start thinking about ways of doing something, you know, all the questioning and answering, and telling oneself, and so on.

I believe that the Haskell developers had similar feelings, as it will turn out.

By the way, first let's check if Bob can really be expressed by the monad class.

I mean, is this true?

> instance Monad Lover where
>     return a = tellMyself a
>     m >>= f = askLover m f

Well, let's check it. Want to see a drunk Bob?

> drunk bob = do newLove "Paula "
>                paula <- tellMyself 5
>                newLove "Jennifer L. "
>                jennyfer <- tellMyself 10
>                newLove "Britney S. "
>                brit <- tellMyself 20
>                newLove "Alex "
>                alex <- tellMyself 15
>                tellMyself (jennyfer * brit * alex)

Let's try:

 *Main> drunk bob
 Lover {loverDiary = ("Paula Jennifer L. Britney S. Alex ",3000)}
 *Main> 

This is definitely the drunk Bob I know.

So it's true, Haskell provides us with a way of describing the inside side of a soul. All this "do" thing we have just seen.

Did you see? No more "askingLover" and "tellingLover", just soul's methods such as "tellMyself" and "newLove".

This is because within that "do-notation" stuff, we are inside our Lover. You can see each line as a soul's answer to an implied soul's question. I told you before, this is Bob's soul talking to herself, without outside-Bob's intervention.

This is all we have to say about a monad in Haskell: it is just the class of types that happen to have a soul. Or, put it differently, it's the class of types that can be described in terms of their internal side, their doing something to themselves.

Who can be a member of such an exclusive class? Sure Bob the Macho Functor Lover can. He has a soul, after all.

So we have some kind of a rule: if you have a soul you are allowed to be a member of this exclusive class of types. If you don't, well, you can be a Macho Functor and nothing more.

Just to make this point clear, take that nice kind of a type we called the Leonard type. I like him, I must tell you the truth.

Still, does he have such a soul that will allow him to be a member of our exclusive club, the Monadic class of types?

Go try yourself:

instance Monad Leonard where
   return a = tellLeonardSelf a
   m >>= f = askLeonard m f

If this is true, then Leonard has a soul that fits Haskell definition of a soul. Otherwise...

Ok, I'm going to tell you anyway: the answer is NO! There must be some kind of regulation, some kind of Law that states that Leonard is unfit for that exclusive club.

Why? I don't know.

There must be some kind of a gatekeeper kind of a type sitting before this Law, and we are not allowed to get in.

What I'd like to point out is that, deciding whether the poor soul we called Leonard has a soul left or not, is a moral decision, not just a technical one. I'm not sure, but as far as I understand it, this is the central question in the movie where our Leonard does what he does.

That is to say, if you really believe you are free and you possess self determination (by the way, I do not), you should start asking yourself some questions about Leonard status in Haskell. I'm saying that just to warn you. This decision has been already taken. I'll add, taken away from you.

Some Haskell guru took that decision for you, and that is it. Period.

You know, those haskell gurus believe to belong to a superior kind of types. Since they have the power to create souls out of thin air, they came to believe they are some kind of a type of a god.

Definitely not just monads, as we poor souls are.

Don't say I didn't tell you: when you start using haskell for your description of the world, keep in mind that in the world you are going to describe types like Leonard are not souls, but just malfunctioning Functors!

Let's go back to Bob. I promised I would introduce Bob to you, and I think I did it. Still, you could be unsatisfied with my introduction. I said a lot about the outside Bob, and very little about his inside side. I just show you a drunk Bob, not the real Bob's soul.

You know, the problem is that I can describe only what I know. Pretty obvious.

What I really wanted to do here, it's just to show you that we could describe Bob's inside if we had enough information.

And you do not have such information, because you don't know Bob.

But you know that I do.

So I'll try to tell you just what I know. If you like it, ok, otherwise, well, your business.

It was one of those stormy nights and I came over to Bob's apartment, down town, with a couple of bottles of a quite strong red wine. We, I mean me and Bob, hate white wine... females' stuff... And when we are alone, I must confess that, we behave very much like Macho Functors.

But we are all alone, and nobody can judge us.

Bob was rolling one of his giant spliff with some weed he got somewhere (he wouldn't tell you where no matter what).

The radio was playing one of those dreadful Dial Sessions, and when Bird misses the entrance in Lover Man, Bob lit up the joint and stared at me. The sound of an almost dying alto sax was filling the room, mixing with the strong smell of weed when I stared back.

In that very moment I believed, and still believe, I had a glimpse of Bob's soul.

I may be wrong, but this is what I believe I saw:

> whoLovedBy bob = do newLove "Andrea "
>                     andrea <- tellMyself 1 
>                     newLove "Bob "
>                     bob <- tellMyself 1
>                     tellMyself (andrea + bob)
 *Main> whoLovedBy bob
 Lover {loverDiary = ("Andrea Bob ",2)}
 *Main> 

Wait a second. This is not true, I'm just kidding... myself.

In that very moment this is precisely what I saw:

whoLovedBy bob = do newLove "Andrea "
                    andrea <- tellMyself 1 
                    tellMyself (andrea + (whoLovedBy bob))

This is all I know about Bob. He loves me, but I'm not the only one.

- Andrea Rossato