Silent Leaf silent.leaf0 at gmail.com
Fri May 20 19:09:32 UTC 2016

```yes, this definition of bind2 looks kinda "frightening". if fact it's
simpler than it looks: (.::) merely takes two functions, then the three
next parameters applied to the result of this special composition, will be
applied to the second parameter, before the result be given as input for
the first parameter.

it must be compared with (.), which only allows the second function to get
one single parameter, before the result of this application becomes the
first parameter of the first function of the composition, after which any
supplementary parameter applied to the whole will go to the left function:
> (left . right) a b c d e = left (right a) b c d e
By comparison:
> (left .:: right) a b c d e = left (right a b c) d e

in the first equation above, defining (.), let's say `right` has type a ->
b -> c -> d. then `left` will get as first parameter, a partial function,
aka (right a :: b -> c -> d). but, in the second equation, `right` gets all
of its three parameters (a, b and c), returning a value of type `d`, before
`left` gets said result-value as its own first parameter, and then possibly
get other parameters of its own (here, d and e).

thus with bind2:
bind2 f ma mb = (join .:: liftM2) f ma mb = join (liftM2 f ma mb)

Now, in my opinion, the point-free style definition of (.::), aka
composition of (.) with itself, three time, is way overkill (better use a
lambda to clarify the purpose), but maybe is it better in terms of
performance or whatever. it's certainly shorter, and when you know what it
entails, it's simple, but it can easily frighten anyone else.

if one wants to understand this (subjectively overkill) point-free
definition,
(.::) = (.) . (.) .(.)
better do the opposite action that leads to point free style, aka, better
name and reveal variables. To make it more readable, i'll define first:
dot = (.)
f .:: g = (dot . dot . dot) f g
= (dot . dot) (dot f) g
= (dot . dot) (f .) g
= dot (dot (f .)) g
= dot ((f .).) g
= ((f . ) .) . g
this expansion (or whatever you call it), solely uses the basic rule (a .
b) c = a (b c), or, with "pollution" around, (w . a . b) c d = (w . a) (b
c) d = w (a (b c)) d.
in the case of b = dot = (.), and c = f, you get (dot f) = (f .), aka,
partially applied composition of f with "something" (the implicit
parameter).

now, this weird
((f .) .) . g = f .:: g
is as we said, directly equivalent to
\f g a b c -> f (g a b c)
indeed:
>   f .:: g
> = (((f .) .) . g) a b c -- structure equivalent to (x.g) a b c
> = ((f .) .) (g a) b c   -- to (w .) (g a) b c   [with x = (w.) and w = (f
.)]
> = ((f .) . (g a)) b c   -- to (w . (g a)) b c = (w . v) a b
> = (f .) ((g a) b) c     -- to (f.) (v b) c = (f.) (g a b) c -- as v = g a
> = (f  . (g a b)) c      -- to (f . k) c   [with k = (g a b)]
> = f ((g a b) c) = f (g a b c)  -- to f (k c)
which is what we thought (.::) was.
simply put, every dot in
> (((f .) .)  .  g)  a  b  c
will allow, first, with the dot to the right, that g, as right side of a
function composition, take the first argument that follows (here a),
becoming a binary partial app (g a);
> ((f .) . (g a))  b  c -- first dot was used
then, this binary partial app (g a) being now the right side of another
composition (second, aka middle dot), will get a new argument of its own
(b), making it an unary partial app (g a b)
> (f . (g a b))  c -- second dot was used
and the last dot the the extreme left, at last, allows (g a b) to take its
last argument before finally the result be inputed to the function f:
> f (g a b c)

I hope it clarifies everything for anyone interested and that didn't know

Le vendredi 20 mai 2016, Tilmann <t_gass at gmx.de> a écrit :
> Thank you for the references. I like the term 'bind2'. I had a look at
Prelude.Generalized. Wow!
>
> bind2 = join .:: liftM2;
> (.::) = (.) . (.) . (.)
>
> Am 20.05.16 um 04:50 schrieb Silent Leaf:
>
> The interesting bit is, the following function > \φ ma mb -> join (pure φ
<*> ma <*> mb) which i like to write as follows using ((&) = flip (\$))
[infixl 1] > \φ ma mb -> pure φ <*> ma <*> mb & join (but it's just
personal taste) is very similar to (=<<), aka (flip (>>=)) except the first
argument (here φ) has type (a -> b -> m c) instead of (a -> m b), and of
course the lambda above takes an added argument too (mb). Some could call
it "bind2" (even if it's the flipped version of (>>=) that is being
generalized), and well, some do. For those interested, there are several
options are available to import it (along possibly with some of its
siblings), from several libraries. (List possibly non exhaustive.)
your problem become btw then: > doIt = bind2 update a b
>
> _______________________________________________
> Beginners mailing list