Intuitive idea of ​​using the arrow operator

Today I had a few hours of fun trying to understand what the arrow operator application in Haskell does. Now I am trying to verify the correctness of my understanding. In short, I found that to use the arrow operator

 (f <*> g <*> h <*> v) z = f z (g z) (h z) (v z)

Before continuing, I know this discussion , but found that it is very confusing and much more complicated than I hope I got today.

To understand that applicative I started by defining the applicative arrow in the base

instance Applicative ((->) a) where
    pure = const
    (<*>) f g x = f x (g x)

and then continued to study what expressions

(f <*> g <*> h) z

and

(f <*> g <*> h <*> v) z

output when expanding.

From the definition we get that

 f <*> g = \x -> f x (g x)

Since it (<*>)remains associative, then

 f <*> g <*> h = (f <*> g) <*> h
               = (\x -> f x (g x)) <*> h
               = \y -> (\x -> f x (g x)) y (h y)

therefore

 (f <*> g <*> h) z = (\y -> (\x -> f x (g x)) y (h y)) z
                   = (\x -> f x (g x)) z (h z)
                   = (f z (g z)) (h z)
                   = f z (g z) (h z)

The last step is related to the fact that the application function remains associative. Similarly

 (f <*> g <*> h <*> v) z = f z (g z) (h z) (v z)

This, for me, gives a very clear intuitive idea of ​​what the application of the arrow does. But is this true?

To check the result, I performed, for example, the following:

λ> ((\z g h v -> [z, g, h, v]) <*> (1+) <*> (2+) <*> (3+)) 4
[4,5,6,7]

which corresponds to the result obtained above.

Before doing the extension above, I found this application very difficult to understand, because extremely complex behavior can be the result of its use due to currying. In particular, in

 (f <*> g <*> h <*> v) z = f z (g z) (h z) (v z)
Functions

may return other functions. Here is an example:

λ> ((\z g -> g) <*> pure (++) <*> pure "foo" <*> pure "bar") undefined
"foobar"

In this case, it is z=undefinedignored by all functions, because the pure x z = xfirst function also ignores the construction z. In addition, the first function accepts only two arguments, but returns a function that takes two arguments.

+4
source share
1 answer

Yes, your calculations are correct.

+4
source

Source: https://habr.com/ru/post/1688344/


All Articles