Archive for March, 2012

monads for the layman

March 11th, 2012

I've done a fair bit of coding in Haskell, yet I could never fully understand monads. And if you don't get monads then coding Haskell is... tense. I could still get things done with some amount of cargo culting, so I was able to use them, but I couldn't understand what they really were.

I tried several times to figure it out, but all the explanations seemed to suck. People are so excited by the universality of monads that they make up all kinds of esoteric metaphors and the more of them you hear about the less you understand. Meanwhile there's no simple explanation to be found. That's when they're not simply too eager to skip ahead to equations that have them weeping like an art critic in front of the Mona Lisa and tell you all about the monadic laws as it that helps.

Fortunately, help is at hand, for today I will show you the first truly good explanation of monads I've ever seen, written by the charming Dan Piponi in the distant 2006 (I rather wish I had found it sooner). What I will do here is use Dan's method to explain it, using some python examples for easier comprehension, and keep it even more basic.

Rationale

monads_primitive_funcsIt's good to get this one straightened out right off the bat. Basically, it's nice to be able to have some piece of data that you can pass to any number of functions, however many times you want, and in whatever order you want. Imagine them lined up one after another like a pipeline, and your data goes through it. In other words: function composition. We like that because it makes for clear and concise code.

To achieve this we need functions that can be composed, ie. have the same signature:

def inc(x):
    return x+1

def double(x):
    return x*2

print "Primitive funcs:", double( inc(1) )
# Primitive funcs: 4

Logging functions

monads_logging_funcsSometimes, however, you find that you want to add something to a function that is not strictly necessary to participate in the pipeline. Something that is more like metadata. What if you wanted your functions to also log that they had been called?

def inc_log(x):
    return inc(x), "inc_log called."

def double_log(x):
    return double(x), "double_log called."

# This will not work properly:
print "Logging funcs:", double_log( inc_log(1) )
# Logging funcs: ((2, 'inc_log called.', 2, 'inc_log called.'), 'double_log called.')

# What we wanted:
# Logging funcs: (4, 'inc_log called.double_log called.')

Now, instead of each function taking one input and giving one output, it gives two outputs. So what happened when we ran it was this:

  1. inc_log received 1
  2. inc_log returned (2, 'inc_log called.')
  3. double_log received (2, 'inc_log called.')
  4. double_log returned ((2, 'inc_log called.', 2, 'inc_log called.'), 'double_log called.')
    Instead of doubling the number it doubled the tuple.

Restoring composability (bind)

monads_bindSo how can we solve this? It's not that hard. If you look at the diagram you see that inc_log produces two outputs, yet double_log should only receive one of these. The other should still be saved, somehow, and then joined with the output of double_log after it's finished executing. So we need a wrapper around double_log to change the arguments it receives and change the arguments it returns!

def bind(g):
    def new_g(pair):
        f_num, f_str = pair
        g_num, g_str = g(f_num)
        return g_num, f_str + g_str
    return new_g

new_double_log = bind(double_log)

print "Logging funcs:", new_double_log( inc_log(1) )
# Logging funcs: (4, 'inc_log called.double_log called.')

The name "bind" is not the most self explanatory imaginable, but what the wrapper does is just what we said in the description:

  1. Receive a pair of values.
  2. Call double_log with the first of these values.
  3. Receive a new pair of values from double_log.
  4. Return a third pair of values that we construct from the other pairs.

The key thing to notice is this: we have "adapted" double_log to be a function that accepts two inputs and returns two outputs. We could use the wrapper on any number of other functions with the same "shape" as double_log and chain them all together this way, even though their inputs don't match their outputs!

Mixing function types

monads_decSo far so good, but what if we now we want to mix logging functions with primitive functions in our pipeline?

def dec(x):
    return x-1

# This will not work:
new_dec = bind(dec)
print "Logging funcs:", new_dec( inc_log(1) )

Granted dec is not a logging function, so we can't expect it to do any logging. Still, it would be nice if we could use it without the logging.

But we can't use bind with dec, because bind expects a function with two outputs. dec simply does not have have the shape of a logging functions, so we are back to square one. Unless...

Using bind with primitive functions

Unless we could fake it, that is. And make dec look like a logging function. In the diagram we can see that there is a gap between the end point of dec and that of bind. bind is expecting two outputs from dec, but it only receives one. What if we could plug that gap with a function that lets the first output through and just makes up a second one?

def unit(x):
    return x, ""

monads_liftYes, just like that! Except that now we have two functions dec and unit, and we don't want to think of them as such, because we really just care about dec. So let's wrap them up so that they look like one!

def lift(func):
    return lambda x: unit( func(x) )

lifted_dec = lift(dec)
new_dec = bind(lifted_dec)

print "Logging funcs:", new_dec( inc_log(1) )
# Logging funcs: (1, 'inc_log called.')

So lift does nothing more than calling dec first, then passing the output to unit and that's it. dec+unit now has the shape of a logging function and lift wraps around them both, making the whole thing into a single function.

And with the lifted dec (a logging function should anyone inquire), we use bind as we've done with logging functions before. And it all works out!

The log says that we've only called inc_log. And yet dec has done its magic too, as we see from the output value.

Conclusions

If you look back at the diagram you might think we've gone to a lot of trouble just to call dec, quite a lot of overhead! But that's also the strength of this technique, namely that we don't have to rewrite functions like dec in order to use them in cases we hadn't anticipated. We can let dec do what it's meant for and do the needed plumbing independently.

If you look back at the code and diagrams you should see one other thing: if we change the shape of logging functions there are two functions we need to update: bind and unit. These two know how many outputs we're dealing with, whereas lift is blissfully ignorant of that.

ti va la teoria o la pratica?

March 10th, 2012

Ci sono delle occasioni in cui si vorrebbe avere una conversazione più approfondita, comunque bisogna sbrigarsi entro un certo orario prestabilito. Allora si fanno domande un po' banali, un po' ingenue, cui non ci sono risposte molto soddisfacenti.

Una volta mi è stato chiesto: tu preferisci avere a che fare con la teoria oppure con la pratica? Non mi ricordo cosa risposi, però più tardi mi accorsi che non era una domanda molto sensata.

In fondo non esistono quelle due cose separatamente. Di solito si parte da uno scopo preciso, per esempio: disintasare il lavandino perché non scorre bene l'acqua.

Quindi si fa un lavoretto per risolvere il problema. Magari facendolo si scopre che cosa ha causato l'intasamento. Per esempio: si sono trovati dei pezzi troppo grandi per poter passare facilmente attraverso le tubature. Bene, abbiamo un'ipotesi: bisogna evitare pezzi troppo grandi, altrimenti s'intasa il lavandino. Se questo succede di nuovo avremo l'opportunità di confermare oppure confutare l'ipotesi che abbiamo fatto.

Nel frattempo, potremmo applicare l'ipotesi nella speranza di anticipare il problema.

Dunque, siamo passati dalla pratica alla teoria e poi, applicando la teoria, si torna di nuovo alla pratica. In effetti, questa è una catena di cui fanno parte i due concetti. Non ha molto senso chiedersi quale dei due è più importante, più utile ecc.

La teoria si fonda sulle fondamenta di un'esperienza. Senza sperimentazione non c'è teoria. Invece la pratica necessita della teoria per riuscire meglio nelle cose che si fanno. Non c'è dubbio che un medico istruito riuscirà molto meglio nel curare un paziente che un dilettante. Però è altrettanto vero che il medico ha bisogno non soltanto di istruirsi teoricamente ma anche di fare un bel po' di pratica per capire come applicare questa teoria nei vari casi che incontrerà. Altrimenti rimarrà una competenza molto meno utile.

il tempismo nello scrivere

March 9th, 2012

È stato detto da comici professionisti che durante lo spettacolo una battuta trasmessa dal comico al pubblico ha una sua esistenza nel tempo. Cioè, bisogna sapere come raccontare una barzelletta, il tono da usare, dove mettere l'enfasi e così via, ma anche dove mettere le pause, quanto far aspettare il pubblico per poi farlo ridere ancora più forte. In questo senso il tempo è fondamentale. Non bisogna fare troppo in fretta, ma neanche aspettare troppo. Una battuta riesce quando è impiegata proprio nel momento giusto, quando c'è da usufruire, diciamo, una tensione, un'aspettativa che vuol essere appagata.

Ecco, spesso nello scrivere provo una sensazione analoga. È chiaro che non si tratta di un pubblico, però questo senso di tempismo mi molesta ogni tanto. Spesso mi viene in mente qualcosa che potrebbe essere un argomento di cui scrivere, comunque sono fuori di casa oppure sono a letto la sera. Mi sembra che se avessi l'opportunità di elaborare quest'idea nel momento stesso potrebbe venir fuori qualcosa di bello, però se devo aspettare qualche ora non è più lo stesso.

È come ricevere un regalo. Fin quando è sempre un regalo confezionato e non si capisce che ci sia dentro, si può aspettare a lungo. Però appena cominci a rompere l'involucro e scopri anche soltanto il colore dell'oggetto che sta dentro è già cominciato il processo della scoperta che non si lascia interrompere per essere ripreso tranquillamente più tardi.

Va beh! Non è l'analogia più esatta, però rende l'idea almeno un po'.

voglio la prescrizione, beninteso

March 8th, 2012

- Buongiorno, ho una prescrizione da effettuare.

- Ha ricevuto una prescrizione dal medico intende?

- Cioè, sì, in effetti. Ecco, desidero essere prosciolto per prescrizione.

- E perché?

- Lo è stato un mio amico. Dice che è una sensazione veramente indimenticabile: la tensione, l'orrore, la paura di finire in carcere, e infine il rilievo, la celebrazione sfrenata.

- Sì, capisco. Comunque temo che lei abbia malinteso. Essere prosciolto per prescrizione non ha niente a che vedere con una prescrizione medica.

- Come sarebbe?

- Vede, la prescrizione in questo caso è una vicenda legale, si tratta di un processo criminale in cui pare sia scattata la prescrizione. Vuol dire che il processo è stato in corso troppo a lungo.

- Lei mi mette in testa una gran confusione. Allora che devo fare per ottenere la prescrizione prosciolta?

- Non è la prescrizione che viene prosciolta, è l'imputato, cioè colui che è processato, che viene prosciolto. Prosciolto l'imputato per prescrizione, cioè prosciolto a causa della prescrizione.

- Il deputato?

- L'imputato.

- Allora devo farmi imputare qualcosa? Ma ciò non fa male da morire?

- No, non deve farsi amputare niente. Senta, adesso bisogna che io passi alla persona seguente, perché per lei non posso far niente. Forse sarebbe meglio per lei farsi altri amici con interessi diverse nella vita.

gli dei

March 7th, 2012

- Lo sai dove sono finiti gli dei?

- Gli dei dici? No, per niente. È da tempo che non se ne sente parlare più. Però a volte mi chiedo cosa sia successo.

- Hai ragione, una volta c'era un fracasso enorme intorno a loro. Si costruivano templi, chiese, si formavano sciamani, rabbini.

- Però sicuramente si fanno preti nuovi da qualche parte ancora?

- Infatti. Comunque, il loro campo professionale si sta sempre restringendo.

- In che senso?

- Nei bei tempi gli dei erano tanti. Si stavano comodissimi in quel splendido palazzo sull'Acropoli; giocavano a carte, sorseggiavano bibite, c'era una comunità. Adesso invece ce n'è rimasto uno solo.

- Poveraccio.

- Già. E invece di sfogarsi con gli amici ha a che fare soltanto con i preti che gli stanno sempre sulle palle adorandolo, leccandogli i piedi e chiedendo favori. Che tristezza.

- Se uno mi viene a adorare un giorno, va bene, non gli dico niente. Ma se poi torna ogni giorno lo butto fuori a calci. Bisogna far capire quando è superato il limite.

- E invece i preti facevano costruire un palazzo per lui, e poi si stavano dentro tutti i giorni, pure chiedendosi perché lui non li veniva a trovare. Magari se fossero andati via lui sarebbe venuto a fermarsi lì ogni tanto per il fine settimana.

- Ma quegli dei di prima non mi sembravano tanto seri. Talvolta severi, però molto giocosi anche.

- Erano greci, sai. Quindi sapevano che cos'è l'allegria. Invece quelli norreni erano molto più tristi. Alcuni erano pure ricoverati per depressione, specie d'inverno che non finisce mai da quelle parti.