简体   繁体   中英

Haskell- composing three functions in weird way

I have three functions xyz and a function called functionComposer.

I want functionComposer to have as arguments the functions xyz and to return me a function that uses the result of y and z as arguments into x and applies x.

In mathematical notation: x(y(a),z(b))

Im NOT asking for this : functionComposer xyz = xyz

For example:

double x = x + x

summer x y = x + y

functionComposer summer double double = summer (double) (double) 

if x = 2 the result should be 8 (2+2)+(2+2)

You can also use the applicative instance for (->) a like so

import Control.Applicative


funcComp summer double1 double2 = summer <$> double1 <*> double2

Or the monad instance

funcComp summer double1 double2 = liftM2 summer double1 double2

The way to understand this is that for (->) a , both the applicative and the monad instance are meant to "parametrize" over the function value that double1 and double2 both accept.

Using your notation:

functionComposer summer double1 double2 = \x -> summer (double1 x) (double2 x) 

The \\x -> ... represents the function mapping x to the ... .

Note I had to give different names to the double function argument, since in general you want to compose different functions.

I somehow feel as if you wanted a confusing series of dots anyways, so:

functionComposer :: (c -> d -> e) -> (a -> c) -> (b -> d) -> a -> b -> e
functionComposer x y z = (. z) . (x . y)

which comes “naturally” from

functionComposer x y z a = (x . y) a . z

But why stop there?

functionComposer x y = (. (x . y)) . flip (.)

No, more:

functionComposer x = (. flip (.)) . flip (.) . (x .)

More!

functionComposer = (((. flip (.)) . flip (.)) .) . (.)

You're basically evaluating y and z "in parallel 1 ". The most fundamental combinator to express this is (***) :: Arrow f => fac -> fbd -> f (a, b) (c, d) . The result of that you want to feed to x , so basically you'd like to write

           x . (y***z)            -- or  x <<< y***z

Now that doesn't quite do the trick because the arrow combinators work with tuples. So you need to uncurry x . Much the same way, if you want the entire thing to accept the arguments in the normal curried fashion, then you must curry out the (a,b) tuple. Easy enough though:

functionComposer :: (c -> d -> e) -> (a -> c) -> (b -> d) -> a -> b -> e
functionComposer x y z = curry $ uncurry x <<< y *** z

1 Mind, I don't mean parallel in the multithreading sense, only "semantically parallel".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM