Capita solo a me?

Una storiella di cosa mi è capitato ieri pomeriggio. E poi ho continuato a pensarci; mi tornava in mente a tradimento, anche la notte. Per cui racconto tutto anche se non ci faccio una bella figura 😯 ma chissene 🧙‍

Tutto è partito da questo tweet: Finally someone explained monads in a way that is actually possible to understand.

Seguendo il link si finisce su Quora, qui: How would you explain the purpose and benefit of monads to a non-programmer?

Panicz è un tipo tosto, già visto altre volte, è un little [non tanto little] schemer 😁
Il post è lungo e impegnativo. Parte bene anche se –secondo me– prende la cosa un tantino troppo alla lunga, dai siamo tutti programmatori, magari non consapevoli ma sì, yepp.

Inizia con l’esempio del calcolo del fattoriale in pseudo-assembly. Ehi! quando io ho cominciato, in Fortran, si programmava così 👽
Anche l’evoluzione dell’esempio è quasi-Fortran, mi sa che in futuro ne riparlo.
Panicz poi introduce l’astrazione ed ecco Haskell

factorial 0 = 1
factorial n = n * factorial(n - 1)

che possiamo ridurre a

factorial n = fold (*) [1..n]

Però una cosa: Note that the above formulation is ambiguous, because we don’t know the order in which expressions should be reduced. If we interpret the expression as (((a ▽ b) ▽ c) ▽ d), we get a left fold, and if we interpret it as (a ▽ (b ▽ (c ▽ d))), we get a right fold.

Ecco qui mi sono perso. Cerrrto colpa mia, solo mia ma… adesso vi conto.

Non ho resistito e ho lanciato GHCi

OK, come previsto ma con (-) si ha

Verifico, è semplice e poi c’è la definizione lì sopra delle due funzioni… E qui il dramma: il -7 non mi viene.

In questi casi so benissimo che sono io che sto sbagliando, che basterebbe scrivere su carta (come si faceva una volta, come dovrei fare sempre, mi conosco, so di essere pasticcione…) e tutto diventa chiaro, così:

(2 - (3 - (4 - 10)))

e ovviamente

Ma non sono stato così razionale. Ho risolto mentalmente l’equazione, sbagliando di nuovo 👿

Panico 👿
No, non mi sono ricordato che in questi casi devo smettere, andare a farmi un caffè o due passi, ho ben quattro cani che adorano le passeggiate anche se sono in aperta campagna, volendo possono farsele da soli, anche se non è notte e non si deve necessariamente abbaiare.

Insomma, non me lo so spiegare ma ci ho messo parecchio prima di decidermi a operare passo-passo, così

(2 - (3 - (4 - 10))) =
(2 - (3 - (-6))) =
(2 - (3 + 6)) =
(2 - 9) =
-7

OK! E sì le parentesi più esterne non sono necessarie ma l’abitudine –mia, il Lisp.

C’è un ulteriore motivo (recondito direi, se sapessi cosa vuol dire) che mi ha panicato e continua a panicarmi: il tutorial che sto seguendo alla fine di ogni lezione propne esercizi; di solito semplici ma Haskell non sono ancora riuscito a farlo mio, è diverso dagli altri linguaggi. Gli esercizi sono senza soluzione, e chissà se quello che ho scritto è vero. Poi proseguendo di solito si scopre che la soluzione viene data nelle trattazioni successive. Intanto panico 👿

Ma sono uscito fuori tema. Stavo scrivendo delle monadi come le vede Panicz.

Panicz ci racconta delle notazioni algebriche: it may or may not be useful to know that mathematicians call a set with an associative operation a semigroup. […] Of course, mathematicians also came up with a name for semigroups with identity element: they are called monoids. (Moreover, if the each element has its inverse element, then this structure is called a group, and is the subject of study of a vast branch of algebra called Group theory.)

For example, strings with concatenation operation form a monoid, where the empty string is the neutral element. But perhaps more importantly, functions with the operation of function composition form a monoid, where the neutral element is of course the identity function. Sì ho saltato la parte relativa all’elemento neutro.

Having the notion of identity element solves yet another problem. Recall the formulation of fold that I gave above. It did not specify what should the value of a fold over an empty list be. Intuitively, the sum of all the elements of an empty list should be 0, for example. For the same reason, the product of all elements of an empty list should be 1.

However, the idea of folding is not limited to monoid, or not even to the things of the same kind. The variants of fold that are most commonly used in Haskell take an additional argument, the “initial value” e, so that, for example, you can understand foldl ▽ e [a,b,c,d] as ((((e ▽ a) ▽ b) ▽ c) ▽ d) and foldr ▽ e [a,b,c,d] as (a ▽ (b ▽ (c ▽ (d ▽ e)))).

Altra digressione qui su version control, poi si passa al lambda calculus, salto che c’è spiegato bene di là. Mica finisce qui, ci sono le callbacks e la pyramid of doom.

E poi:

Monads, finally
So far we have seen that we can usually avoid the pyramid of doom rather easily by introducing new syntactic forms to our language. However, for some reason many programmers do not like to use languages whose syntax is based on s-expressions and prefer other syntaxes that correspond better to their whims. Since these syntaxes make the introduction of new syntactic forms to the language really difficult, they come up with other means to avoid the pyramid of doom.

They suggest that it is a good idea to have a single special form that is able to convert nesting into sequencing, that is implicitly parameterized with some sort of composition operator (this special form is called “do-notation” in Haskell and “for-comprehension” in Scala). The implicit parametrization occurs with the help from the type system (for example, in Haskell it makes use of the mechanism called type classes).

Salto i dettagli, e arrivo al dunque. [T]he developers of Haskell decided that its sequencing operator should be parameterized not only with the composition operator (which is written as >>= and pronounced “bind” in Haskell), but there should also be a “unit” operator that does nothing interesting — or to be more precise, it does nothing in some particular sense (it is called return in Haskell, probably to confuse programmers with background in imperative programming).

Arguably, there are some “monadic laws” that ought to be satisfied by these operators. […]

These laws may remind you the definition of monoids. This should explain at least some bit of the popular phrase “monads are just monoids in the category of endofunctors, what’s the problem?”.

The problem is that neither the notion of category, nor the notion of an endofunctor gives any clues whatsoever with regard to sequencing. […] Salto polemica su IO. E:

TL; DR they allow to replace nesting with sequencing in languages that have a poor support for macros but offer sufficiently elaborate type systems. And they probably allow some programmers to look smart. The name “monad” is terrible, because it focuses on some irrelevant (and unnecessary) details, giving no clue of the purpose whatsoever (truly, the name “sequencing” would be way better).

Insomma Panicz è chiaro ma forse troppo polemico. E, per quanto mi riguarda, mi conferma che le mie difficoltà con Haskell non sono solo mie. Ma insisto, quando il gioco si fa duro… (inizio-cit.) 😉

🤩

Posta un commento o usa questo indirizzo per il trackback.

Trackback

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo di WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione /  Modifica )

Google photo

Stai commentando usando il tuo account Google. Chiudi sessione /  Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione /  Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione /  Modifica )

Connessione a %s...

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.

%d blogger hanno fatto clic su Mi Piace per questo: