2

I'm trying to write a function, pipe that takes a list of mathematical functions where pipe [f1,...,fn] x should return f1(f2(...(fn x))) I've set it up such that:

pipe :: [(a -> a)] -> (a -> a)
pipe fs   = foldLeft f base fs
  where
    f a x =    
    base  = 

-- >>> pipe [] 3
-- 3
--
-- >>> pipe [(\x -> x+x), (\x -> x + 3)] 3
-- 12
--
-- >>> pipe [(\x -> x * 4), (\x -> x + x)] 3
-- 24

whats the best way to go about this using foldl? Thanks!

Scott Myers
  • 226
  • 9
  • 30
  • What do *you* think `foldLeft` and `base` should be? Do you have no intuition at all? PS the function is called `foldl`, there is no such thing as `foldLeft`. (And I'm not convinced this will work as desired with a left fold, although I'd have to think about it - it's usually more natural in Haskell to use a right fold.) – Robin Zigmond Nov 07 '19 at 00:45
  • I'm very new to haskell -- but imagining that foldLeft is identical to foldl. Just a little stunted as to where to start – Scott Myers Nov 07 '19 at 00:51
  • Start by writing down the types that `f` and `base` must have. (I accidentally wrote `foldLeft` in the first sentence of my above comment, where I meant `f`.) That should make it reasonably obvious what they should be. – Robin Zigmond Nov 07 '19 at 00:52
  • I figure that `base` should be `fs`. I've added expected results of the functions to my post. `f` should be a function that somehow stacks the function of the previous term with 'fs' at the center. I could be far off here, im pretty lost. – Scott Myers Nov 07 '19 at 01:03
  • I understand what you want the function to do (and `foldl` does work just as well as `foldr`, I checked). But `base` cannot be `fs`, as they have different types. Seriously, write down the types of `f` and `base` - it will make things a lot clearer. You'd be surprised how far you can get with Haskell just by making sure types match up. Another way to think about `base` is: what do you expect `pipe` to do if given an empty list? – Robin Zigmond Nov 07 '19 at 01:07
  • Ok, I've written down the types of `f` and `base` as: `f :: (a -> b -> a)` and base should be an integer I'm still unsure as to how to apply the term of the list as a function in `f` – Scott Myers Nov 07 '19 at 01:14
  • Those types aren't correct. Compare the type of `foldl` with those of your list and the final output that you want. – Robin Zigmond Nov 07 '19 at 01:17
  • Another way to look at it is: you want to combine a bunch of functions into a single function. What tools (= functions or operators) does Haskell provide for doing that? – Robin Zigmond Nov 07 '19 at 01:18

2 Answers2

2

with foldl it should be:

pipe :: [(a -> a)] -> (a -> a)
pipe fs = foldl (\rs f -> f . rs) id fs 

or with an eta:

pipe :: [(a -> a)] -> (a -> a)
pipe = foldl (\rs f -> f . rs) id 

with another eta:

pipe :: [(a -> a)] -> (a -> a)
pipe = foldl (.) id 

taking your example:

pipe [(\x -> x * 4), (\x -> x + x)] 3
=> 24 
developer_hatch
  • 15,898
  • 3
  • 42
  • 75
0

pipe can actually be made much simpler than you'd think, and there's no need to use the rather inefficient foldl (you can see this even in your own parentheses—they're right-associative): just flip (foldr id). Steps to get there:

pipe [f1,...,fn] x
f1 (f2 (... (fn x)))            -- your definition of pipe
id f1 (id f2 (... (id fn x)))   -- id x = x
foldr id x [f1,...,fn]          -- the definition of foldr