简体   繁体   中英

About mapping on the eventual result of a multi-argument function

I known that r -> a is a Functor in a , and that fmap = (.) for it.

This means that when I do fmap fg , with g:: r -> a , f is applied to the result of g as soon as the latter is fed with a value of type r . However, if a is a function type, eg a unary function b -> c , then there's a difference between applying f to that function (which is what happens in reality) and applying f to the eventual result of g (which could be desirable in some cases; couldn't it?).

How do I map on the eventual result of g ? In this case of g:: r -> b -> c it seems easy, I can just uncurry $ fmap f $ curry g . But what if also c is a function type?

Or, in other words, how do I map on the final result of multi-variable function? Is the curry / uncurry trick necessary/doable in general?

(Related question here .)

As it's apparent from comments/answers, I have not realized I was essentially asking the same question I've already asked some days ago. Probably it was not apparent to me because of how I got here. Essentially, what led me to ask this question is another one storming in my head:

If I can use liftA2 (&&) , liftA2 (||) , and similar to combine unary predicates, how do I combine binary predicates? To answer to this, I played around a bit in GHCi, and came up with this

liftIntoBinaryFunc p = \q r -> curry $ (liftA2 p) (uncurry q) (uncurry r)

which would allow doing something like this:

-- some binary predicate
distanceLE3 x y = 3 >= abs (x - y)
sameSign x y = ((==) `on` signum) x y

-- function to lift into binary functions
liftIntoBinaryFunc p = \q r -> curry $ (liftA2 p) (uncurry q) (uncurry r)

-- lifting && into binary functions to Bool
and' = liftIntoBinaryFunc (&&)

-- combining 
pred = distance3 `and'` sameSign

-- using
p 3 18   -- False
p 3 1    -- True
p 3 (-1) -- False

However, this question too generalizes to how do I combine predicates of arbitrary (though common) arity? , and probably the answer is the same.

If you'd like to accept n arguments and then apply f , you may call fmap n times. So, if g:: r -> b -> c , then

(fmap . fmap) f g

will apply f to the value of type c that results from applying g to two arguments, while if h:: a -> b -> c -> d -> e -> f -> g , then

   a      b      c      d      e      f
(fmap . fmap . fmap . fmap . fmap . fmap) f h

will apply f to the value of type g that results from applying h to 6 arguments.

r -> b -> c is r -> (b -> c) and so (fmap. fmap) (f:: c -> d) (g:: r -> b -> c):: r -> b -> d :

> foo :: (c -> d) -> (r -> (b -> c)) -> r -> (b -> d) ;
  foo = fmap . fmap

foo :: (c -> d) -> (r -> b -> c) -> r -> b -> d

> bar :: (c -> d) -> (r -> (b -> (t -> c))) -> r -> (b -> (t -> d)) ;
  bar = fmap . fmap . fmap

bar :: (c -> d) -> (r -> b -> t -> c) -> r -> b -> t -> d

But you will have to know how many nested levels are there, to compose the fmaps accordingly, or use approaches from your other recent question .

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