Evaluation of expression str a b = ((.).(.)) (0 -) (+) 1 2

335 views Asked by At

Could you explain to me how the following expression works:

str a b = ((.).(.)) (0 -) (+) 1 2

I have checked it and GHCi said that it is -3 but I don't understand why.

I checked as well the following:

*Main> :t ((.).(.))
((.).(.)) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c

but it doesn't helped me.

Any idea?

3

There are 3 answers

1
kqr On BEST ANSWER

The operator (.).(.) is sometimes given an alias:

(.:) = (.).(.)

You can view it as (.), only it works when the second function takes two arguments. So this works, for example:

sqrtsum = sqrt .: (+)
-- sqrtsum 4 5 ==> 3.0

This will take two numbers, sum them and then take the square root of the sum. The .: alias sort of makes visual sense, as you can imagine the colon representing the function of two arguments being connected to the function of one argument.

If you want to, you can view the type signature of (.) like this:

(.) :: (b -> c) -> (a -> b) -> (a -> c)

This means that (.) takes two functions a -> b and b -> c and "pipes them together" and returns a function from a directly to c. The operator (.:) works similarly – you can write its type signature as

(.:) :: (b -> c) -> (a1 -> a2 -> b) -> (a1 -> a2 -> c)

What it does is that it takes one function a1 -> a2 -> b and one function b -> c and it gives you back a function that goes directly from a1 and a2 to c.

If you want to verify this type for yourself, you can work your way to (.:) with the signature for (.). I will not do this for you, in part because it might end up being a wall of text and in part because it's a great exercise for you in reasoning about your code! If you need a place to start, remember that

(.) :: (b -> c) -> (a -> b) -> (a -> c)

In the expression

(.).(.)

which can also be written as

(.) (.) (.)

the two argument functions to (.) (a -> b and b -> c) are both (.) themselves – so you get to replace a lot of as and bs and cs with what they really represent!

2
phipsgabler On

You'll learn the most if you expand the lambda terms by hand. Or, if you're lazy, use a tool.

Anyway, here it is:

dot = λf.λg.λx.f (g x)

dot dot dot (0 -) + 1 2
⇒   (λg.λx.dot (g x)) dot (0 -) + 1 2
⇒   (λx.dot (dot x)) (0 -) + 1 2
⇒   dot (dot (0 -)) + 1 2
⇒   (λg.λx.dot (0 -) (g x)) + 1 2
⇒   (λx.dot (0 -) (+ x)) 1 2
⇒   dot (0 -) (+ 1) 2
⇒   (λg.λx.0 - (g x)) (+ 1) 2
⇒   (λx.0 - (+ 1 x)) 2
⇒   0 - (+ 1 2)
⇒   0 - 3
0
Ankur On

Types : (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c

Values: (0 -)_______(+)_______________1___2

1 is a, 2 is a1, (+) is (a -> a1 -> b) .. apply (+) to 1 and 2 you get 3 which is now value of b.

(0 -) is (b -> c), apply 3 (which was b above) to this you will get (0-3) i.e -3 which is value of c and this whole function returns c hence -3 is the final answer.