Haskell composition with two parameters

I am trying to understand functional programming through Haskell, and I have so many problems with function layout.

In fact, I have two functions:

add:: Integer -> Integer -> Integer add xy = x + y sub:: Integer -> Integer -> Integer sub xy = x - y 

I want to be able to build them. It does not make any sense, but it is for the purpose of training.

What I tried:

 foo:: (Integer -> Integer) -> (Integer -> Integer) -> Integer foo = add . sub 

What I understood:

Haskell uses functions with only one argument, so we return a new function to execute after each function is executed.

So, the first Integer is the type of the parameter, and the second is the return type of the generated function, which should add the second number.

This will return another function ( sub ) that will do the same thread (returning a function with parameters, etc.)

I'm right?

Here is my actual error code:

 src\Main.hs:23:7: Couldn't match type `Integer' with `Integer -> Integer' Expected type: Integer -> (Integer -> Integer) -> Integer Actual type: Integer -> Integer -> Integer In the first argument of `(.)', namely `add' In the expression: add . sub src\Main.hs:23:13: Couldn't match type `Integer -> Integer' with `Integer' Expected type: (Integer -> Integer) -> Integer Actual type: Integer -> Integer -> Integer Probable cause: `sub' is applied to too few arguments In the second argument of `(.)', namely `sub' In the expression: add . sub 

I do not know what I am doing wrong.

Can you help me understand a little more of this error so that I can find a solution?

+5
source share
2 answers

For function

 add :: Integer -> Integer -> Integer 

It is useful to remember (as you yourself indicated in the section “What I understand”) that -> in the credits is associated on the right, i.e. the above type is the same as

 add :: Integer -> (Integer -> Integer) 

Now consider the type (.) :

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

This means that in the expression

 (.) add 

b in type (.) is Integer , and c corresponds to Integer -> Integer . Another way to write this

 b ~ Integer c ~ Integer -> Integer 

So, we get

 (.) add :: (a -> Integer) -> a -> (Integer -> Integer) 

If you now apply (.) add to sub , the compiler notices that a -> Integer cannot be done according to Integer -> Integer -> Integer .

I suspect that you probably want the composition to have three arguments: two for applying sub to, and the result of this — along with the third argument — is passed to add . Thus, a possible definition, which is two functions, will be

 foo :: (Integer -> Integer -> Integer) -> (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer foo fgxy = f (gxy) y 

For what it's worth, there is a problem associated with this: compiling a function with two arguments with one argument function, for example. making up

+6
source

I want to be able to build them. It does not make any sense, but it is for the purpose of training.

This is actually the problem here. How do you want to create them? Let's look at some possible compositions:

 foo xy = sub x (add xy) -- x + y - x = y foo xy = sub y (add xy) -- x + y - y = x foo xy = sub x (add yy) -- 2 * y - x foo xy = sub y (add yy) -- 2 * y - y = y foo xy = sub y (sub y (add xx)) -- 2 * x - 2 * y 

In doing so, we will check the type error by checking the types from hand:

 type I = Integer -- otherwise the lines are going to be very long (.) :: (b -> c ) -> (a -> b ) -> a -> c add :: I -> (I -> I) sub :: I -> (I -> I) -- ||||||||||||| (.) add :: (a -> I ) -> a -> (I -> I) -- ^^^^^^^^^^^^^ 

As you can see, (.) add already requires that another function can be of type a -> Integer for an arbitrary a . But sub type Integer -> (Integer -> Integer) (remember, (->) is the correct associative).

Now, what can you do to fix this? First, consider the proposed type of foo :

 foo :: (Integer -> Integer) -> (Integer -> Integer) -> Integer 

This is indeed a very interesting type of function. How would you actually get your result? You just have two functions, but no values:

 > foo fg = 

You can solve this problem using the fixed point of one of the functions, and then apply the other:

 > let x = fx in gx > > example = foo (const 12) (+1) -- returns 13 

But that’s not what you had in mind, is it? At the moment, it is very important to think about the semantics of your composition. Since this is not clear, you cannot write a general way to create both functions here.

However, if you really meant

 foo :: Integer -> Integer -> Integer -> Integer foo xyz = add (sub xy) z 

then it is possible with

 foo = (add .) . sub 

So

 (.) add :: (a -> I) -> a -> (I -> I) (.) ((.) add) :: (a -> b -> Integer) -> a -> b -> Integer -> Integer 

But (add .) . sub (add .) . sub is actually not that simple. You'd better write the exact definition of foo if this function was your original goal.

+4
source

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


All Articles