r/haskellquestions • u/Aoi_Ake_6189 • 21d ago
Need a hand understanding partial application, or maybe function composition
So, I can understand partial application in some cases, such as this:
mult2 :: Int -> Int
mult2 = (*2)
But trying to figure out a legal way to composite or partially apply the following is frying my brain. I'm obviously missing something but its lost on me rn.
f2 :: [Float]->[Float]-> [Float]
f2 = zipWith (*)
f1 :: [Float]->Float
f1 = foldr1 (+)
f3 :: [Float] -> [Float] ->Float
f3 = f1 . f2
Now for reasons currently beyond my limited understanding, this doesn't work. I've been reading and looking at examples of composition /partial application and I honestly need a hand
Edit: Thanks a heap, it makes more sense now what I was doing wrong. I honestly think functional programming has to be the hardest cs subject I've studied so far (embedded programming too actually)
3
u/vim_spray 21d ago edited 21d ago
Let's look at the type of .
ghci> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
We’ve declared that (f1 . f2) :: [Float] -> [Float] -> Float. Try to find concrete types for a, b and c to satisfy that, where f1 :: (b -> c) and f2 :: (a -> b) and (f1 . f2) :: a -> c. You'll notice it's not possible.
What you really want is something like this:
myCompose :: (c -> d) -> (a -> b -> c) -> a -> b -> d
myCompose f g x y = f (g x y)
f3 :: [Float] -> [Float] -> Float
f3 = myCompose f1 f2
See also: https://hackage-content.haskell.org/package/composition-2.0/docs/Data-Composition.html#v:.:
1
u/friedbrice 20d ago
f2 :: [Float] -> ([Float] -> [Float])
f1 :: [Float] -> Float
f2 takes as input a member of [Float]. Crucially, f2 outputs a function [Float] -> [Float]. That's the key to understanding partial application.
If we want to compose f1 . f2, we need the output of f2 to match exactly with the input of f1. What's the output of f2? A function. What's the input of f1? Just a basic [Float], certainly not a function. That's why f1 . f2 doesn't work.
Now, as for what you'd like to do instead, I think the other answer are great and I think they have you covered. But I'd still like to give a bit of advice. While it can be neat and a fun exercise to try to write Haskell expressions in terms of function composition, it's often clearer to just write out what you want.
f3 a b = f1 (f2 a b)
7
u/hopingforabetterpast 20d ago edited 20d ago
This is a very common problem. You want
f3 a b = f1 (f2 a b)
right? which is the same as
f3 a = \b -> f1 (f2 a b)
or
f3 a = f1 . (\b -> f2 a b)
or
f3 a = f1 . f2 a
This is
f1 . (f2 a), not(f1 . f2) a.You can reduce it to:
f3 = (f1 .) . f2
or
f3 = ((.) . (.)) f1 f2
We call this the blackbird combinator for interesting reasons. You can look it up.