I know there are other posts about this, but mine is slightly different.
I have a function that performs the task of foldl, using foldr. I have the solution given to me, but would like help understanding.
foldlTest:: (b -> a -> b) -> [a] -> (b -> b)
foldlTest f xs = foldr (\x r b -> r (f b x))
(\b -> b)
xs
And It is called using something like this:
foldlTest (-) [1,2,3] 10 = -4
First thing I understand is that my function takes in 2 arguments, but 3 are given in the above test case. This means that the 10 will take part in a lambda expression I assume.
1) Does the 10 take the place of the b in b -> b? (then the b would be the initial accumulator value)
What I don't understand is what the (\x r b -> r (f b x)) part does.
2) What is the value of each of the variables? I am very confused about this lambda function.
3) What exactly does the lambda function do and how is it different from a regular foldr?
OK, since none of our resident Haskell experts has yet stepped up to explain this, I thought I'd have a go. Please everyone, feel free to correct anything you see wrong, because I'm really just feeling my way towards the answer here, and the following will by its very nature be a bit rambling.
First, as always in Haskell, it's a good idea to look at the types:
Prelude> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Since we're just interested in lists here, and not generic Foldables, let's specialise this to:
foldl :: (b -> a -> b) -> b -> [a] -> b
and compare with the function you've been given:
foldlTest:: (b -> a -> b) -> [a] -> (b -> b)
Since Haskell functions are curried, which is another way of saying that -> arrows in type signatures are right associative, the last pair of parentheses there is unnecessary, so this is the same as:
foldlTest:: (b -> a -> b) -> [a] -> b -> b
Comparing with that for foldl above, we see that they're identical except for the fact that the last two parameters - the [a] and the b - have been flipped over.
So we can already observe that, while the library function foldl takes a fold function, a starting accumulator, and a list to fold, to produce a new accumulator, the foldlTest version takes a fold function, a list to fold, and a starting accumulator, to produce a new accumulator. That sounds like the exact same thing, which it is, but if we now reintroduce the pair of brackets which I took off a few steps ago, we see that foldlTest, in the form you've shown, can be thought of as:
taking a fold function and a list, and producing a function b -> b which describes how folding over the list transforms the initial accumulator into the final result.
Note in particular that what it returns, in this formulation, is indeed a function.
So now we're ready to look at the actual implementation that you've seen:
foldlTest f xs = foldr (\x r b -> r (f b x))
(\b -> b)
xs
I'll be the first to admit that this is rather complicated, even confusing. As ever, lets examine the types.
The input types are easy. We know from the above discussion that f has type b -> a -> b, and xs has type [a].
OK, what about that lambda? Let's take it in stages:
It takes 3 arguments, x, r and b, in that order.
The result of the function call is r (f b x). This already tells us a lot, if we sit down and think about it!
For one, we know f has type b -> a -> b, so from f b x we know that b has type b and x has type a.
As for r, we see that it must be a function, because it's applied to f b x. And we know the latter has type b (from the type signature of f). So r has type b -> c, for some type c.
Therefore our complicated lambda function has the type a -> (b -> c) -> b -> c, where c is some type we haven't yet determined.
Now comes a key point. This lambda is presented as the first argument (the fold function) to the foldr function. Therefore it must have the type d -> e -> e, for some types d and e.
Remember that functions are curried, and although it seems like the lambda's signature takes 3 arguments, we can reduce it to 2 by rewriting as a -> (b -> c) -> (b -> c). That's an exact match for the signature we know foldr is looking for, with d equal to a and e equal to b -> c.
And it we specialise foldr's signature so that it accepts this type of function, we find that it is:
foldr :: (a -> (b -> c) -> (b -> c)) -> (b -> c) -> [a] -> (b -> c)`
We still don't know what c is - but we don't have to wonder much longer. The above is the signature for a fold which goes over a list of as, and produces a function from b to c. The next argument to foldr, which is of type b -> c, is given (by the implementation we're trying to decipher) as \b -> b. This is just the identity function, of course, and crucially it is a function from a type to itself. So the b -> c type must actually be b -> b, or in other words c was the same as b all along!
So that lambda must have the following type:
a -> (b -> b) -> (b -> b)
It takes an a, and an endomorphism on b (that just means a function from b to itself), and returns another endomorphism on b. And this is the function we will fold the list of as with, taking the identity function as a starting point, to produce the endomorphism b -> b that will implement the left fold we're after.
The above type signature on its own doesn't give us much clue of how to implement it, given that a and b could be anything. However, we do have our function f that relates them - recall it takes a b and an a, and produces a b. Given that (by undoing the currying again), the above function requires us, given an a, a b -> b function, and a b, to produce another b, I can only see two non-trivial ways to do it:
apply the function to the b, then apply f to the a and the result.
apply f to the a and the b, then apply the b -> b function to the result
The second of these two is exactly what that lambda you are asking about does, as hopefully is now obvious from looking at it. (The first option would be written \x r b -> f (r b) x. I'm not actually sure what overall effect this would produce, although I haven't thought about it much.)
I've covered a lot of ground, although it feels like more than it really is, because I've tried to be very painstaking. To recap, what the foldlTest function does is, given a list of as and a function f :: b -> a -> b, produces a function b -> b that is built by starting with the identity function, and walking right-to-left along the list, changing the current function r :: b -> b to the one that sends b to r (f b x) - where x :: a is the element of the list we are currently at.
That's a rather algorithmic description of what foldlTest does. Let's try to see what it does to an actual list - not a concrete one, but let's say a 3-element list [a1, a2, a3]. We start with the identity function \b -> b, and successively transform it into:
b -> f b a3 (recall that r starts as the identity function)
b -> f (f b a2) a3 (this is just substituting the previous function as r into \b -> r (f b x), with a2 now playing the role of x)
b -> f (f (f b a1) a2) a3
I hope you can now see that this looks an awful lot like folding the list from the left with the same function f. And by "looks an awful lot like", I actually mean it's identical! (If you haven't seen or tried it before, try to write out the successive stages of foldl f b [a1, a2, a3] and you'll see the identical pattern.)
So apologies again that this has been a bit rambling, but I hope this has given you enough information to answer the questions you asked. And don't worry if it makes your brain hurt a bit - it does mine too! :)
The answer you've been given (not the one on SO, the one you cited in your question) seems to be more difficult than necessary. I assume it is intended to teach you some aspects of folds, but apparently this is not working well. I try to show what's happening and in the process answer your questions.
3) What exactly does the lambda function do and how is it different from a regular foldr?
The whole thing just builds a left fold (foldl) out of a right fold (foldr) and flips the last two arguments. It is equivalent to
foldTest f = flip (foldr (flip f))
foldTest f = flip (foldl f)
and it does so in a rather obscure way, by accumulating a function and does the flipping via a lambda.
1) Does the 10 take the place of the b in b -> b? (then the b would be the initial accumulator value) What I don't understand is what the (\x r b -> r (f b x)) part does.
Yes, correct. The 10 takes to role of the initial accumulator of a left fold.
2) What is the value of each of the variables? I am very confused about this lambda function.
To get an intuition as to what is happening, I find it helpful to do the actual lambda calculus step by step:
foldTest (-) [1,2,3] 10
foldTest (-) (1:(2:(3:[]))) 10
-- remember the definition of foldTest which is given in a point-free way
foldlTest f xs = foldr (\x r b -> r (f b x)) (\b -> b) xs
-- add the hidden parameter and you get
foldlTest f xs b' = (foldr (\x r b -> r (f b x)) (\b -> b) xs) b'
-- apply that definition with f = (-), xs = (1:(2:(3:[]))), b' = 10
(foldr (\x r b -> r ((-) b x)) (\b -> b) (1:(2:(3:[])))) 10
(foldr (\x r b -> r (b - x)) (\b -> b) (1:(2:(3:[])))) 10
-- the inner lambda function is curried, thus we can write it as
-- \x r (\b -> r (b - x)), which is equivalent but will be handy later on.
(
foldr (\x r -> (\b -> r (b - x))) (\b -> b) (1:(2:(3:[])))
) 10
-- keep in mind foldr is defined as
foldr f' b'' [] = b''
foldr f' b'' (x:xs') = f' x (foldr f' b'' xs')
-- apply second row of foldr with f' = (\x r -> (\b -> r (b - x))),
-- b'' = (\b -> b), x = 1 and xs' = (2:(3:[]))
(
(\x r -> (\b -> r (b - x))) 1 (foldr (\x r -> (\b -> r (b - x))) (\b -> b) (2:(3:[])))
) 10
-- apply accumulation lambda for the first time with x = 1,
-- r = foldr (\x r -> (\b -> r (b - x))) (\b -> b) (2:(3:[])) gives
(
\b -> (foldr (\x r -> (\b -> r (b - x))) (\b -> b) (2:(3:[]))) (b - 1)
) 10
-- now we repeat the process for the inner folds
(
\b -> (
foldr (\x r -> (\b -> r (b - x))) (\b -> b) (2:(3:[]))
) (b - 1)
) 10
(
\b -> (
(\x r -> (\b -> r (b - x))) 2 (foldr (\x r -> (\b -> r (b - x))) (\b -> b) (3:[]))
) (b - 1)
) 10
(
\b -> (
\b -> (foldr (\x r -> (\b -> r (b - x))) (\b -> b) (3:[])) (b - 2)
) (b - 1)
) 10
(
\b -> (
\b -> (
foldr (\x r -> (\b -> r (b - x))) (\b -> b) (3:[])
) (b - 2)
) (b - 1)
) 10
(
\b -> (
\b -> (
(\x r -> (\b -> r (b - x))) 3 (foldr (\x r -> (\b -> r (b - x))) (\b -> b) [])
) (b - 2)
) (b - 1)
) 10
(
\b -> (
\b -> (
\b -> (foldr (\x r -> (\b -> r (b - x))) (\b -> b) [])) (b - 3)
) (b - 2)
) (b - 1)
) 10
(
\b -> (
\b -> (
\b -> (
foldr (\x r -> (\b -> r (b - x))) (\b -> b) []
) (b - 3)
) (b - 2)
) (b - 1)
) 10
-- Now the first line of foldr's definition comes in to play
(
\b -> (
\b -> (
\b -> (
\b -> b
) (b - 3)
) (b - 2)
) (b - 1)
) 10
-- applying those lambdas gives us
(
\b -> (
\b -> (
\b -> (
\b -> b
) (b - 3)
) (b - 2)
) (b - 1)
) 10
-- So we can see that the foldTest function built another function
-- doing what we want:
(\b -> (\b -> (\b -> (\b -> b) (b - 3)) (b - 2)) (b - 1)) 10
(\b -> (\b -> (\b -> b) (b - 3)) (b - 2)) (10 - 1)
(\b -> (\b -> b) (b - 3)) ((10 - 1) - 2)
(\b -> b) (((10 - 1) - 2) - 3)
(((10 - 1) - 2) - 3)
((9 - 2) - 3)
(7 - 3)
4
By the definition of foldlTest, we have
foldlTest (-) xs b = foldr g n xs b
where
n b = b
g x r b = r (b - x)
By the definition of foldr, we have
foldr g n [x,y,z] = g x (foldr g n [y,z])
but also
foldr g n [x,y,z] b = g x (foldr g n [y,z]) b -- (1)
---- r -----------
= foldr g n [y,z] (b-x)
(when used "inside" the foldlTest), and so, by repeated application of (1),
= g y (foldr g n [z]) (b-x)
= foldr g n [z] ((b-x)-y)
= g z (foldr g n [] ) ((b-x)-y)
= foldr g n [] (((b-x)-y)-z)
= n (((b-x)-y)-z)
= (((b-x)-y)-z)
Thus an expression which is equivalent to the left fold is built by the right fold straight up, because g is tail recursive. And thus
foldlTest (-) [1,2,3] 10
-- [x,y,z] b
==
(((10 - 1) - 2) - 3))
==
foldl (-) 10 [1,2,3]
and so we see that no, the b in the n = (\b -> b) does not accept the 10, but rather it accepts the whole expression equivalent to the left fold that has been built by the right fold.
But yes, 10 is the initial accumulator value in the expression equivalent of the left fold, as intended, that has been built by the right fold.
Related
Say you have a list of numbers, [1,2,3,5,6,7,8,9,11,12,15,16,17]
and you want a function that takes that as an input and returns something like
[[1,3],[5,9],[11,12],[15,17]] or alternatively maybe
[(1,3), (5,9), (11,12), (15,17)]
how would this be done? all of the solutions i've found online are very very long and quite convoluted, when this seems like such an easy problem for a functional language like haskell
So we have a list of numbers,
xs = [1,2,3,5,6,7,8,9,11,12,14,16,17] -- 14 sic!
We turn it into a list of segments,
ys = [[x,x+1] | x <- xs]
-- [[1,2], [2,3], [3,4], [5,6], ..., [11,12], [12,13], [14,15], [16,17], [17,18] ]
we join the touching segments,
zs = foldr g [] ys
-- [[1,4], [5,10], [11,13], [14,15], [16,18]]
where
g [a,b] [] = [[a,b]]
g [a,b] r#([c,d]:t) | b==c = [a,d]:t
| otherwise = [a,b]:r
and we subtract 1 from each segment's ending value,
ws = [[a,b-1] | [a,b] <- zs]
-- [[1,3], [5,9], [11,12], [14,14], [16,17]]
All in all we get
ranges :: (Num t, Eq t) => [t] -> [[t]]
ranges = map (\[a,b] -> [a,b-1]) . foldr g [] . map (\x -> [x,x+1])
where
g [a,b] [] = [[a,b]]
g [a,b] r#([c,d]:t) | b==c = [a,d]:t
| otherwise = [a,b]:r
Simple and clear.
edit: or, to be properly lazy,
where
g [a,b] r = [a,x]:y
where
(x,y) = case r of ([c,d]:t) | b==c -> (d,t) -- delay forcing
_ -> (b,r)
update: as dfeuer notes, (a,a) type is better than [a,a]. Wherever [P,Q] appears in this code, replace it with (P,Q). This will improve the code, with zero cost to readability.
I would definitely prefer the alternative representation to the first one you give.
ranges :: (Num a, Eq a) => [a] -> [(a,a)]
ranges [] = []
ranges (a : as) = ranges1 a as
-- | A version of 'ranges' for non-empty lists, where
-- the first element is supplied separately.
ranges1 :: (Num a, Eq a) => a -> [a] -> [(a,a)]
ranges1 a as = (a, b) : bs
where
-- Calculate the right endpoint and the rest of the
-- result lazily, when needed.
(b, bs) = finish a as
-- | This takes the left end of the current interval
-- and the rest of the list and produces the right endpoint of
-- that interval and the rest of the result.
finish :: (Num a, Eq a) => a -> [a] -> (a, [(a, a)])
finish l [] = (l, [])
finish l (x : xs)
| x == l + 1 = finish x xs
| otherwise = (l, ranges1 x xs)
To solve the Rosetta Code problem linked in the comment above, this isn't really quite an optimal representation. I'll try to explain how to match the representation more precisely later.
So one might do it like the idea from #Will Ness on the stateful folding or mine under the same answer. All explanations are to be found there. Besides, if you get curious and want to read more about it then have a look at Haskell Continuation Passing Style page. I am currently trying to gerealize this in such a way that we can have a variant of foldr1 in a stateful manner. A foldS :: Foldable t => (a -> a -> b) -> t a -> b. However this is still not general stateful folding. It's just tailored to this question.
ranges :: (Ord a, Num a) => [a] -> [[a]]
ranges xs = foldr go return xs $ []
where
go :: (Ord a, Num a) => a -> ([a] -> [[a]]) -> ([a] -> [[a]])
go c f = \ps -> let rrs#(r:rs) = f [c]
in case ps of
[] -> [c]:r:rs
[p] -> if p + 1 == c then rrs else [p]:(c:r):rs
*Main> ranges [1,2,3,5,6,7,8,9,11,12,15,16,17]
[[1,3],[5,9],[11,12],[15,17]]
I haven't had time to test any edge cases. All advices are welcome.
So I've been doing this program which receives a function f, a number a and a list b and it should return a list [a, f(a,b), f(f(a,b),b, ..] iterating through the list b and using recursion. Do you guys know how I can optimize my code?
calculate :: (a -> b -> a) -> a -> [b] -> [a]
help :: (a -> b -> a) -> a -> [b] -> [a]
help f a (x:xs) = (f a x) : (calculate f (f a x) xs)
help f a [] = []
calculate f a b = a : (help f a b)
calculate f a b = tail . concatMap (replicate 2) . scanl f a $ b.
The replicate bit is probably in error. If so, then simply calculate = scanl.
This translates the code, as the "[a, f(a,b), f(f(a,b),b, ..]" from the text contradicts it (and it contradicts the text itself, which talks of "iterating through the list b").
So what I have so far is something like this:
combs :: [[Char]]
combs = [[i] ++ [j] ++ [k] ++ [l] | i <- x, j <- x, k <- x, l <- x]
where x = "abc"
So this is the working function for n = 4, is there any way to make this work for an arbitrary number of generators? I could program in for n = 1, 2, 3 etc.. but ideally need it to work for any given n. For reference, x is just an arbitrary string of unique characters. I'm struggling to think of a way to somehow extract it to work for n generators.
You can use replicateM:
replicateM :: Applicative m => Int -> m a -> m [a]
E.g.:
generate :: Num a => Int -> [[a]]
generate = flip replicateM [1,2,3]
to generate all possiible lists of a given length and consisting of elements 1..3.
As far as I know, you can not construct list comprehension with an arbitrary number of generators, but usually if you do something with arbitrary depth, recursion is the way to do it.
So we have to think of solving this, in terms of itself. If you want all possible strings that can be generated with the characters in x. In case n = 0, we can generate exactly one string: the empty string.
combs 0 = [""]
so a list with one element [].
Now in case we want to generate strings with one characters, we can of course simply return x:
combs 1 = x
and now the question is what to do in case n > 1. In that case we can obtain all the strings with length n-1, and and for each such string, and each such character in x, produce a new string. Like:
combs n = [ (c:cs) | c <- x, cs <- combs (n-1) ]
Note that this makes the second case (n = 1) redundant. We can pick a character c from x, and prepend that to the empty string. So a basic implementation is:
combs :: Int -> [[Char]]
combs 0 = [""]
combs n = [(c:cs) | c <- x, cs <- combs (n-1)]
where x = "abc"
Now we can still look for improvements. List comprehensions are basically syntactical sugar for the list monad. So we can use liftA2 here:
import Control.Applicative(liftA2)
combs :: Int -> [[Char]]
combs 0 = [""]
combs n = liftA2 (:) x (combs (n-1))
where x = "abc"
we probably also want to make the set of characters a parameter:
import Control.Applicative(liftA2)
combs :: [Char] -> Int -> [[Char]]
combs _ 0 = [""]
combs x n = liftA2 (:) x (combs (n-1))
and we do not have to restrict us to characters, we can produce a certesian power for all possible types:
import Control.Applicative(liftA2)
combs :: [a] -> Int -> [[a]]
combs _ 0 = [[]]
combs x n = liftA2 (:) x (combs (n-1))
First I would translate the comprehension as a monadic expression.
x >>= \i -> x >>= \j -> x >>= \k -> x >>= \l -> return [i,j,k,l]
With n = 4 we see we have 4 x's, and generally will have n x's. Therefore, I am thinking about a list of x's of length n.
[x,x,x,x] :: [[a]]
How might we go from [x,x,x,x] to the monadic expression? A first good guess is foldr, since we want to do something with each element of the list. Particularly, we want to take an element from each x and form a list with these elements.
foldr :: (a -> b -> b) -> b -> [a] -> b
-- Or more accurately for our scenario:
foldr :: ([a] -> [[a]] -> [[a]]) -> [[a]] -> [[a]] -> [[a]]
There are two terms to come up with for foldr, which I will call f :: [a] -> [[a]] -> [[a]] and z :: [[a]]. We know what foldr f z [x,x,x,x] is:
foldr f z [x,x,x,x] = f x (f x (f x (f x z)))
If we add parentheses to the earlier monadic expression, we have this:
x >>= \i -> (x >>= \j -> (x >>= \k -> (x >>= \l -> return [i,j,k,l])))
You can see how the two expressions are looking similar. We should be able to find an f and z to make them the same. If we choose f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a') we get:
f x (f x (f x (f x z)))
= (\x a -> a >>= \a' -> x >>= \x' -> return (x' : a')) x (f x (f x (f x z)))
= f x (f x (f x z)) >>= \a' -> x >>= \x' -> return (x' : a')
= f x (f x (f x z)) >>= \a' -> x >>= \l -> return (l : a')
= (f x (f x z) >>= \a' -> x >>= \k -> return (k : a')) >>= \a' -> x >>= \l -> return (l : a')
= f x (f x z) >>= \a' -> x >>= \k -> x >>= \l -> return (l : k : a')
Note that I have reversed the order of i,j,k,l to l,k,j,i but in context of finding combinations, this should be irrelevant. We could try a' ++ [x'] instead if it was really of concern.
The last step is because (a >>= \b -> c) >>= \d -> e is the same as a >>= \b -> c >>= \d -> e (when accounting for variable hygiene) and return a >>= \b -> c is the same as (\b -> c) a.
If we keep unfolding this expression, eventually we will reach z >>= \a' -> … on the front. The only choice that makes sense here then is z = [[]]. This means that foldr f z [] = [[]] which may not be desirable (preferring [] instead). Instead, we might use foldr1 (for non-empty lists, and we might use Data.NonEmpty) or we might add a separate clause for empty lists to combs.
Looking at f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a') we might realise this helpful equivalence: a >>= \b -> return (c b) = c <$> a. Therefore, f = \x a -> x >>= \x' -> (x' :) <$> a. Then also, a >>= \b -> c (g b) = g <$> a >>= \b -> c and so f = (:) <$> x >>= \x' -> x' <$> a. Finally, a <*> b = a >>= \x -> x <$> b and so f = (:) <$> x <*> a.
The official implementation of sequenceA for lists is foldr (\x a -> (:) <$> x <*> a) (pure []), exactly what we came up with here too. This can be further shortened as foldr (liftA2 (:)) (pure []) but there is possibly some optimisation difference that made the implementors not choose this.
Last step is to merely come up with a list of n x's. This is just replicate replicate n x. There happens to be a function which does both replication and sequencing, called replicateM replicateM n x.
I was given an assignment to calculate the length of a list using the foldr Haskell function, so I did these two examples
flength :: [a] -> Int
flength = foldr (\ _ n -> n+1) 0
flength' :: [a] -> Int
flength' l = foldr aux 0 l
where
aux _ n = n+1
Then, as a personal challenge, the professor asked us to use the snd function and yesterday I came up with this:
flength'' :: [a] -> Int
flength'' = foldr ((+1).(curry snd)) 0
What I want to happen is that this function will turn the head of the list h and the accumulator 0 into the pair (h,0) then return 0 and after that apply it to the function (+1)
I expected this to be done recursively, effectively giving me the length of the list at the end.
Instead, I get this error message:
[1 of 1] Compiling Main ( f1.hs, interpreted )
f1.hs:54:24: error:
* No instance for (Num (Int -> Int))
arising from an operator section
(maybe you haven't applied a function to enough arguments?)
* In the first argument of `(.)', namely `(+ 1)'
In the first argument of `foldr', namely `((+ 1) . (curry snd))'
In the expression: foldr ((+ 1) . (curry snd)) 0 xs
Failed, modules loaded: none.
Why is this happening and how can I get this code to work?
Let us lay all our tools in front of us, like a good artisan does:
foldr :: (a -> b -> b) -> b -> [a] -> b
snd :: (a, b) -> b
First, we note that snd and foldr do not really fit well. So let's use curry, just like you did, and add curry snd to our small tool library:
foldr :: (a -> b -> b) -> b -> [a] -> b
curry snd :: a -> b -> b
This looks very promising. Now we need to add 1 to the result of curry snd, otherwise we're just writing flip const. Let's start with a lambda:
\a b -> 1 + curry snd a b
= \a b -> ((+1) . curry snd a) b
We can now shove of b and end up with
\a -> (+1) . curry snd a
= \a -> (.) (+1) (curry snd a)
= \a -> ((.) (+1)) (curry snd a)
= \a -> (((.) (+1)) . curry snd) a
Now we can eta-reduce a from both sides too and end up with
(((.) (+1)) . curry snd) = ((+1) . ) . curry snd
Therefore, your third variant would be
flength'' = foldr (((+1) . ) . curry snd) 0
Now, why did you get your error message? You were close with (+1) . curry snd, but the types don't work out:
(+1) :: Int -> Int
-- v v
(.) :: (b -> c) -> (a -> b ) -> a -> c
curry snd :: t -> (x -> x)
^ ^
But in your case, the bs in (.)'s signature didn't match. One of them was an Int, the other was a function.
TL;DR: If you want to write f (g x y) point-free, write ((f.) . g)
I'm trying to write a function that takes a predicate f and a list and returns a list consisting of all items that satisfy f with preserved order. The trick is to do this using only higher order functions (HoF), no recursion, no comprehensions, and of course no filter.
You can express filter in terms of foldr:
filter p = foldr (\x xs-> if p x then x:xs else xs) []
I think you can use map this way:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = concat (map (\x -> if (p x) then [x] else []) xs)
You see? Convert the list in a list of lists, where if the element you want doesn't pass p, it turns to an empty list
filter' (> 1) [1 , 2, 3 ] would be: concat [ [], [2], [3]] = [2,3]
In prelude there is concatMap that makes the code simplier :P
the code should look like:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = concatMap (\x -> if (p x) then [x] else []) xs
using foldr, as suggested by sclv, can be done with something like this:
filter'' :: (a -> Bool) -> [a] -> [a]
filter'' p xs = foldr (\x y -> if p x then (x:y) else y) [] xs
You're obviously doing this to learn, so let me show you something cool. First up, to refresh our minds, the type of filter is:
filter :: (a -> Bool) -> [a] -> [a]
The interesting part of this is the last bit [a] -> [a]. It breaks down one list and it builds up a new list.
Recursive patterns are so common in Haskell (and other functional languages) that people have come up with names for some of these patterns. The simplest are the catamorphism and it's dual the anamorphism. I'll show you how this relates to your immediate problem at the end.
Fixed points
Prerequisite knowledge FTW!
What is the type of Nothing? Firing up GHCI, it says Nothing :: Maybe a and I wouldn't disagree. What about Just Nothing? Using GHCI again, it says Just Nothing :: Maybe (Maybe a) which is also perfectly valid, but what about the value that this a Nothing embedded within an arbitrary number, or even an infinite number, of Justs. ie, what is the type of this value:
foo = Just foo
Haskell doesn't actually allow such a definition, but with a slight tweak we can make such a type:
data Fix a = In { out :: a (Fix a) }
just :: Fix Maybe -> Fix Maybe
just = In . Just
nothing :: Fix Maybe
nothing = In Nothing
foo :: Fix Maybe
foo = just foo
Wooh, close enough! Using the same type, we can create arbitrarily nested nothings:
bar :: Fix Maybe
bar = just (just (just (just nothing)))
Aside: Peano arithmetic anyone?
fromInt :: Int -> Fix Maybe
fromInt 0 = nothing
fromInt n = just $ fromInt (n - 1)
toInt :: Fix Maybe -> Int
toInt (In Nothing) = 0
toInt (In (Just x)) = 1 + toInt x
This Fix Maybe type is a bit boring. Here's a type whose fixed-point is a list:
data L a r = Nil | Cons a r
type List a = Fix (L a)
This data type is going to be instrumental in demonstrating some recursion patterns.
Useful Fact: The r in Cons a r is called a recursion site
Catamorphism
A catamorphism is an operation that breaks a structure down. The catamorphism for lists is better known as a fold. Now the type of a catamorphism can be expressed like so:
cata :: (T a -> a) -> Fix T -> a
Which can be written equivalently as:
cata :: (T a -> a) -> (Fix T -> a)
Or in English as:
You give me a function that reduces a data type to a value and I'll give you a function that reduces it's fixed point to a value.
Actually, I lied, the type is really:
cata :: Functor T => (T a -> a) -> Fix T -> a
But the principle is the same. Notice, T is only parameterized over the type of the recursion sites, so the Functor part is really saying "Give me a way of manipulating all the recursion sites".
Then cata can be defined as:
cata f = f . fmap (cata f) . out
This is quite dense, let me elaborate. It's a three step process:
First, We're given a Fix t, which is a difficult type to play with, we can make it easier by applying out (from the definition of Fix) giving us a t (Fix t).
Next we want to convert the t (Fix t) into a t a, which we can do, via wishful thinking, using fmap (cata f); we're assuming we'll be able to construct cata.
Lastly, we have a t a and we want an a, so we just use f.
Earlier I said that the catamorphism for a list is called fold, but cata doesn't look much like a fold at the moment. Let's define a fold function in terms of cata.
Recapping, the list type is:
data L a r = Nil | Cons a r
type List a = Fix (L a)
This needs to be a functor to be useful, which is straight forward:
instance Functor (L a) where
fmap _ Nil = Nil
fmap f (Cons a r) = Cons a (f r)
So specializing cata we get:
cata :: (L x a -> a) -> List x -> a
We're practically there:
construct :: (a -> b -> b) -> b -> L a b -> b
construct _ x (In Nil) = x
construct f _ (In (Cons e n)) = f e n
fold :: (a -> b -> b) -> b -> List a -> b
fold f m = cata (construct f m)
OK, catamorphisms break data structures down one layer at a time.
Anamorphisms
Anamorphisms over lists are unfolds. Unfolds are less commonly known than there fold duals, they have a type like:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
As you can see anamorphisms build up data structures. Here's the more general type:
ana :: Functor a => (a -> t a) -> a -> Fix t
This should immediately look quite familiar. The definition is also reminiscent of the catamorphism.
ana f = In . fmap (ana f) . f
It's just the same thing reversed. Constructing unfold from ana is even simpler than constructing fold from cata. Notice the structural similarity between Maybe (a, b) and L a b.
convert :: Maybe (a, b) -> L a b
convert Nothing = Nil
convert (Just (a, b)) = Cons a b
unfold :: (b -> Maybe (a, b)) -> b -> List a
unfold f = ana (convert . f)
Putting theory into practice
filter is an interesting function in that it can be constructed from a catamorphism or from an anamorphism. The other answers to this question (to date) have also used catamorphisms, but I'll define it both ways:
filter p = foldr (\x xs -> if p x then x:xs else xs) []
filter p =
unfoldr (f p)
where
f _ [] =
Nothing
f p (x:xs) =
if p x then
Just (x, xs)
else
f p xs
Yes, yes, I know I used a recursive definition in the unfold version, but forgive me, I taught you lots of theory and anyway filter isn't recursive.
I'd suggest you look at foldr.
Well, are ifs and empty list allowed?
filter = (\f -> (>>= (\x -> if (f x) then return x else [])))
For a list of Integers
filter2::(Int->Bool)->[Int]->[Int]
filter2 f []=[]
filter2 f (hd:tl) = if f hd then hd:filter2 f tl
else filter2 f tl
I couldn't resist answering this question in another way, this time with no recursion at all.
-- This is a type hack to allow the y combinator to be represented
newtype Mu a = Roll { unroll :: Mu a -> a }
-- This is the y combinator
fix f = (\x -> f ((unroll x) x))(Roll (\x -> f ((unroll x) x)))
filter :: (a -> Bool) -> [a] -> [a]
filter =
fix filter'
where
-- This is essentially a recursive definition of filter
-- except instead of calling itself, it calls f, a function that's passed in
filter' _ _ [] = []
filter' f p (x:xs) =
if p x then
(x:f p xs)
else
f p xs