Related
Hi I have task for writing a function that takes a list of functions from Int -> Int and a single Int and checks if any function when applied to that Int gives a result which is greater than 5.
This is my solution :
foo :: [Int -> Int] -> Int -> Bool
foo ls = any (>5) . f ls
where f ls v = map ($ v) ls
I would like to know is there a way to write this in single line (without using where or let) with eta reducing last argument (now it is eta reduced but it is not in single line). I tried something like this :
foo ls = any (>5) . flip map ls
But now the problem is call of function that looks like this for it to work
foo [(+3), (*4), (+1)] ($2)
I would like to avoid writin $ for last argument. I tried something like this (and similar to this) :
foo ls = any (>5) . flip map ls ($)
But I always get some kind of error. Be aware that I must not change the type signature, thus the flip.
Is there a way? Sure. Is it readable? No. Haskell's design pushes you away from some common mistakes, like unnecessary mutability or hidden use of (necessary) mutable state. But it makes it exciting to follow the path of other mistakes, like making code point-free in a manner harmful to readability and maintainability.
The thing about point-free definitions is that converting to them is a completely mechanical process (so long as pattern matching isn't involved in the starting definition). There are tools to do it automatically.
Start by writing the definition fully eta-expanded:
foo ls x = any (>5) (map ($ x) ls)
Then throw it into your favorite tool for doing the conversion. http://pointfree.io/ is an online service that will do it.
And it spits out the totally unreadable:
foo = (any (> 5) .) . flip (map . flip id)
Don't use that. It's not worth it.
But maybe you only wanted to eta-contract away one argument, and this is too much? Well, you can do that by cheating a little bit, and pretending the first argument is a value in scope, not an argument, and throwing the following definition in:
foo x = any (>5) (map ($ x) ls)
It returns foo = any (> 5) . flip map ls . flip id, which you then insert the argument back into:
foo ls = any (> 5) . flip map ls . flip id
This is mildly better, thanks to lacking sections of the (.) operator. But it still has flip id in it, which is obfuscation at its simplest.
Don't do it. Exercise restraint. Write code that's easy to read and modify.
Actually, your last trial in the question
foo ls = any (>5) . flip map ls ($)
is already very close to solution.
The only one problem is, considers the definition of ($):
($)::(a -> b) -> a -> b
the first argument of ($) is a function (a->b), but in your case, need be a value a, so just flip ($) swap the order of the arguments of ($) and put it back as:
foo ls = any (>5) . flip map ls . flip ($)
is the function that you want.
Starting with a fully non-reduced definition:
foo ls v = any (>5) (map (\f -> f v) ls)
We can use lambdabot to have a fully eta-reduced solution:
foo = (any (> 5) .) . flip (map . flip id)
However, this looks awful, and should not be recommended to do.
Since you have an applicative list at hand you may simply apply it with the applicative operator <*> as [(+3), (*4), (+1)] <*> [2] to obtain the list of results such as [5,8,3]. Now it's the any :: Foldable t => (a -> Bool) -> t a -> Bool function that comes handy. So all together
checker x = any (>5) $ [(+3), (*4), (+1)] <*> [x]
should do the job. If you need the pointfree version than it would be like
checker = any (>5) . ([(+3), (*4), (+1)] <*>) . pure
I've been trying very hard to grasp the (.) and ($) operators in Haskell. I believe I understand the differences between them well enough, but I am still having a hard time successfully replacing the parentheses in my expressions with these operators.
For example, if I have the expression
print(show(take 5 [1..10]))
I understand how to rewrite it using the (.) and ($) operators
print . show . take 5 $ [1..10]
However, if I had something like
print (show (take (snd (1,5)) [1..10]))
The furthest I can simplify this down to is
print . show . take (snd (1,5)) $ [1..10]
No matter what I try I can not seem to replace those inner parenthesis with the ($) or (.) operator and have it successfully compile. I understand that most Haskellers typically use the ($) and (.) operators over parentheses so I am trying really hard to follow that style as well. If someone could point out how I could rewrite that expression above without using parenthesis I think it would help me use those operators with much more success. Thanks.
Your rewrite...
print . show . take (snd (1,5)) $ [1..10]
... is as good as it gets in terms of readability. The following suggestions will in fact make it more convoluted than necessary; still, knowing such things are possible can, as you say, bring a better appreciation of how ($) and (.) work.
The first function which is applied to [1..10] is...
take (snd (1,5))
... so let's focus on it for a moment. If you were trying to eliminate parentheses there without the rest of the expression, you might end up with...
take . snd $ (1,5)
To reconstruct the original function, we need to apply that to [1..10]. A natural way of doing so would be...
(take . snd $ (1,5)) [1..10]
... but since we are avoiding parentheses, we need extra trickery. There are two immediate options. The first one is passing the list to the function with a ($) section:
($ [1..10]) . take . snd $ (1,5)
Just like (* 2) is a function that takes a number and multiplies it by two, ($ [1..10]) is a function...
GHCi> :t ($ [1..10])
($ [1..10]) :: (Num t, Enum t) => ([t] -> b) -> b
... that takes a function and applies it to [1..10]. (And yes, I have just added a pair of parentheses; however, they are not really being used for grouping -- ($ [1..10]) is just alternative syntax for flip ($) [1..10] -- so I say they don't count :))
At this point, we can complete the expression in the same manner of your original version:
print . show . ($ [1..10]) . take . snd $ (1,5)
The other option is writing the whole function pointfree (that is, without explictly writing the arguments). To do that, let's get back to...
take . snd $ (1,5)
... and leave out the pair for a moment:
take . snd
take . snd is a function...
GHCi> :t take . snd
take . snd :: (a1, Int) -> [a] -> [a]
... that takes a pair and a list and gives back a list. We can, however, also read this type as:
take . snd :: (a1, Int) -> ([a] -> [a])
... that is, we have a function that takes a pair and returns a function. If we compose some function foo with take . snd so that we get foo . take . snd, foo will be applied to the function produced by take . snd. In fact, we have done just that when we used ($ [1..10]) just above. Besides supplying argments, another thing we can do with functions is composing them. And we do have an operator for composing functions...
((print . show) .) . take . snd
... namely, (.). The weird expression within the parentheses is a section of (.), just like the one we used for ($) before, except that this is a left section, and that was a right section. Due to operator precedence shenanigans an extra pair of parentheses is necessary; equally unsatisfactory alternatives include...
(print .) . (show .) . take . snd
... and...
(.) print . (.) show . take . snd
With the pointfree function in our hands, we can supply the arguments in whichever way we feel like -- for instance, like this...
(((print . show) .) . take . snd) (1,5) [1..10]
... or this...
($ [1..10]) . ((print . show) .) . take . snd $ (1,5)
... or even this...
($ [1..10]) . ($ (1,5)) $ ((print . show) .) . take . snd
... or, for something less bizarre:
let f = ((print . show) .) . take . snd in f (1,5) [1..10]
There are indeed many alternatives -- and they all conspire to show how nice your original rewrite was in the first place!
Your final simplification is good and quite readable in the f . g . h $ x style. The main point of that style isn't so much to eliminate parentheses (though it can clean them up and sometimes eliminate them) but as an idiom to make it clear at a glance that a sequence of functions is being applied to something and what those functions are.
With expressions in high school algebra, sometimes you can't eliminate parentheses when you simplify because you're stuck with a fixed set of operators and with a fixed order of operations. That's why parentheses have to be included in high school algebra. If you're stuck with just (.) and ($), I think that's the best you can get.
Eliminating parentheses by adding a new operator
This isn't recommended because your simplified version was just fine and people will have to take time to figure out what the new operator means for little benefit, but I'm adding it just for the sake of completeness.
We're in Haskell instead of high school algebra, so we can add a new operator with whatever precedence. It needs to work like ($) but have a precedence equal to (.) (since it can't be greater than (.), which has the highest precedence).
So, to eliminate all parentheses (except for the tuple) in ghci:
Prelude> let infixr 9 $$$; a $$$ b = a b
Prelude> print . show . take $$$ snd (1, 5) $ [1..10]
"[1,2,3,4,5]"
To eliminate all parentheses:
Prelude> let infixr 9 $$$; a $$$ b = a b
Prelude> let tuple :: a -> b -> (a, b); tuple = (,)
Prelude> print . show . take $$$ snd $$$ tuple 1 5 $ [1..10]
"[1,2,3,4,5]"
I have a simple function, and the desire to make sense of point-free style.
shout :: String -> String
shout input
| null input = []
| otherwise = (toUpper . head $ input) : (shout . tail $ input)
My intuition led me to this
pfShout :: String -> String
pfShout = (toUpper . head) : (shout . tail)
which is complaining about the following for the first argument of the cons cell
Couldn't match expected type 'String -> String'
with actual type '[[Char] -> Char]'
Possible cause: '(:)' is applied to too many arguments
In the expression: (toUpper . head) : (pfShout . tail)
In an equation for 'pfShout':
pfShout = (toUpper . head) : (pfShout . tail)
and complaining about this for the second argument of the cons cell
Couldn't match expected type '[[Char] -> Char]'
with actual type '[Char] -> String'
Probable cause: '(.)' is applied to too few arguments
In the second argument of '(:)', namely '(pfShout . tail)'
In the expression: (toUpper . head) : (pfShout . tail)
In an equation for 'pfShout':
pfShout = (toUpper . head) : (pfShout . tail)
It's clear to me that I can't make a list out of 'String -> String' functions and '[[Char]->Char]', and I'm starting to get a to a place where I'm thinking this just isn't gonna work point-free.
I understand there are other considerations here (like now I'm missing a base-case), but . I also understand I could completely re-write the function to achieve the same effect (like map toUpper). I'm primarily interested in point-free using recursion with the function as it is written.
If it is (or isn't) possible to write this function point-free, what am I missing?
As #n.m noted you can use shout = map toUpper. However it is possible to do this without map or any other fancy functions like foldr, but we need more combinators. We need something that takes our input argument and passes it to two functions toUpper . head and shout . tail and then combines them with :. You propably don't know this function yet, but the <*> operator from applicative has what we need:
(f <*> g) x = f x (g x)
Now we can do something like this:
combine . f <*> g = \x -> combine (f x) (g x) -- [1]
I will let you figure out how exactly to apply this to your problem. ;)
But we still need to express the empty list case somehow. There are multiple ways to do this but the easiest would be the bool from Data.Bool function which is like an if function, together with join from Control.Monad.
-- [2]
bool x _ False = x
bool _ x True = x
join f x = f x x
Now we can do the following:
shout = join $ bool (not null case) (null case) . null
-- Which translates to
shout xs = bool ((not null case) xs) ((null case) xs) (null xs)
Again implementing the two cases is left as an excercise to the reader.
[1]: Instead of (.) you could also use (<$>) which for functions is the same as (.) but (<$>) and (<*>) kind of belong together. You will understand why once you learn about applicatives.
[2]: If you wonder what the reasoning behind the order of the arguments of bool is, the first argument is the False case because Bool is defined like this:
data Bool = False | True
And this order is motivated by the convention that False < True. maybe and either are two other functions that share this exact pattern with bool.
To rewrite anything in a pointfree style, install pointfree or use any one of the online versions (http://pointfree.io or https://blunt.herokuapp.com).
Your expression
\input -> (toUpper . head $ input) : (shout . tail $ input)
translates to
ap ((:) . toUpper . head) (shout . tail)
(You can substitute <*> for ap, they are interchangeable in this case).
But this is not enough. You also need to somehow end the recursion. To do that in the pointfree style you need a pointfree if or a pointfree pattern match which do not seem to exist in Haskell. In theory if could be defined as a built-in function, which would make a pointfree definition possible, but in Haskell it isn't. (One can define such a function, but its implementation would not be pointfree. So you can trade map for Data.Bool.bool, but is there a point?
Combinators like . and $ and even ap are probably not internally pointfree either, but using them doesn't feel like cheating. They only deal with functions, and thus feel somehow more fundamental than bool or map.
The point-free way to do recursion is to use Data.Function.fix, which is explained here: https://en.wikibooks.org/wiki/Haskell/Fix_and_recursion
I started learning Haskell and I encountered a problem I can't just understand. I've got a method used to find value from a list of key-value list (from this page):
let findKey key xs = snd . head . filter (\(k,v) -> key == k) $ xs
I tried fiddling with a bit and decided to get rid of $ sign in this way:
let findKey key xs = snd . head . filter (\(k,v) -> key == k) ( xs )
However, it doesn't even parse (filter applied to too many argumens error). I've read that $ sign is used to simply replace parenthesis and I can't figure out why this simple change of code is bad. Could someone explain it to me?
The infix operator ($) is just "function application". In other words
f x -- and
f $ x
are the same. Since in Haskell parentheses are only used to disambiguate precedence (and for tuple notation and a few other minor places, see comments) we can also write the above in a few other ways
f x
f $ x
(f) x
f (x)
(f) (x) -- and even
(f) $ (x)
In every case, the above expressions denote the same thing: "apply the function f to the argument x".
So why have all this syntax? ($) is useful for two reasons
It has really low precedence so it can stand in for a lot of parentheses sometimes
It's nice to have an explicit name for the action of function application
In the first case, consider the following deeply right-nested function application
f (g (h (i (j x))))
It can be a little difficult to read this and a little difficult to know you have the right number of parentheses. However, it's "just" a bunch of applications so there ought to be a representation of this phrase using ($). Indeed there is
f $ g $ h $ i $ j $ x
Some people find this easier to read. More modern style also incorporates (.) in order to emphasize that the whole left side of this phrase is just a composed pipeline of functions
f . g . h . i . j $ x
And this phrase is, as we saw above, identical to
(f . g . h . i . j) x
which is sometimes nicer to read.
There are also times when we want to be able to pass around the idea of function application. For instance, if we have a list of functions
lof :: [Int -> Int]
lof = [ (+1), (subtract 1), (*2) ]
we might want to map application by a value over them, for instance apply the number 4 to each function
> map (\fun -> fun 4) lof
[ 5, 3, 8 ]
But since this is just function application, we can also use section syntax over ($) to be a bit more explicit
> map ($ 4) lof
[ 5, 3, 8 ]
The operator $ has the lowest priority, so
snd . head . filter (\(k,v) -> key == k) $ xs
is read as
(snd . head . filter (\(k,v) -> key == k)) xs
while your second expression is rather
snd . head . ( filter (\(k,v) -> key == k) xs )
The $ sign isn't magic syntax for replacing parentheses. It's an ordinary infix operator, in every way that an operator like + is.
Putting brackets around a single name like ( xs ) is always equivalent to just xs1. So if that's what the $ did, then you'd get the same error either way.
Try to imagine what would happen if you had some other operator you're familiar with there, such as +:
let findKey key xs = snd . head . filter (\(k,v) -> key == k) + xs
Ignore the fact that + works on numbers so this makes no sense, and just think about the structure of the expression; which terms are being recognised as functions, and which terms are being passed to them as arguments.
In fact, using + there does actually parse and typecheck successfully! (It gives you a function with nonsense type class constraints, but if you fulfill them it does mean something). Lets walk through how the infix operators are resolved:
let findKey key xs = snd . head . filter (\(k,v) -> key == k) + xs
The highest precedence thing is always normal function application (just writing terms next to each other, with no infix operators involved). There's only one example of that here, filter applied to the lambda definition. That gets "resolved", and becomes a single sub-expression as far as parsing the rest of the operators is concerned:
let findKey key xs
= let filterExp = filter (\(k,v) -> key == k)
in snd . head . fileterExp + xs
The next highest precedence thing is the . operator. We've got several to choose from here, all with the same precedence. The . is right associative, so we take the rightmost one first (but it wouldn't actually change the result whichever one we pick, because the meaning of the . is an associative operation, but the parser has no way of knowing that):
let findKey key xs
= let filterExp = filter (\(k,v) -> key == k)
dotExp1 = head . filterExp
in snd . dotExp1 + xs
Note that the . grabbed the terms immediately to its left and right. This is why precedence is so important. There's still a . left, which is still higher precedence than +, so it goes next:
let findKey key xs
= let filterExp = filter (\(k,v) -> key == k)
dotExp1 = head . filterExp
dotExp2 = snd . dotExp1
in dotExp2 + xs
And we're done! + has lowest precedence of the operators here, so it gets its arguments last, and ends up being the top-most call in the whole expression. Note that the + being low precedence prevented the xs being "claimed" as an argument by any of the higher precedence applications to the left. And if any of them had been lower precedence, they would have ended up taking the whole expression dotExp2 + xs as an argument, so they still couldn't have got to xs; putting an infix operator before xs (any infix operator) prevents it from being claimed as an argument by anything to the left.
This is in fact exactly the same way that $ is parsed in this expression, because . and $ happen to have the same relative precedence that . and + have; $ is designed to have extremely low precedence, so it will work this way with almost any other operators involved to the left and right.
If we don't put an infix operator between the filter call and xs, then this is what happens:
let findKey key xs = snd . head . filter (\(k,v) -> key == k) xs
Normal function application goes first. Here we've got 3 terms simply next to each other: filter, (\(k,v) -> key == k), and xs. Function application is left associative, so we take the leftmost pair first:
let findKey key xs
= let filterExp1 = filter (\(k,v) -> key == k)
in snd . head . filterExp1 xs
There's still another normal application left, which is still higher precedence than the ., so we do that:
let findKey key xs
= let filterExp1 = filter (\(k,v) -> key == k)
filterExp2 = filterExp1 xs
in snd . head . filterExp2
Now the first dot:
let findKey key xs
= let filterExp1 = filter (\(k,v) -> key == k)
filterExp2 = filterExp1 xs
dotExp = head . filterExp2
in snd . dotExp
And we're done, the top-most call in the whole expression this time was the left-most . operator. This time xs got sucked in as a second argument to filter; this is sort-of where we want it since filter does take two arguments, but it leaves the result of filter in a function composition chain, and filter applied to two arguments can't return a function. What we wanted was to apply it to one argument to give a function, have that function be part of the function composition chain, and then apply that entire function to xs.
With $ there, the final form mirrors that when we used +:
let findKey key xs
= let filterExp = filter (\(k,v) -> key == k)
dotExp1 = head . filterExp
dotExp2 = snd . dotExp1
in dotExp2 $ xs
It's parsed exactly the same way as when we had +, so the only difference is that where + means "add my left argument to my right argument", $ means "apply my left argument as a function to my right argument". Which is what we wanted to happen! Huzzah!
TLDR: The bad news is that $ doesn't work by just wrapping parentheses; it's more complicated than that. The good news is that if you understand how Haskell resolves expressions involving infix operators, then you understand how $ works. There is nothing at all special about it as far as the language is concerned; it's an ordinary operator you could define yourself if it didn't exist.
1 Parenthesising an operator like (+) also just gives you exactly the same function denoted by +, but now it doesn't have the special infix syntax, so this does affect how things are parsed in this case. Not so with ( xs ) where it's just a name inside.
"$ sign is used to simply replace parenthesis" is pretty much correct – however, it effectively parenthesises everything to both sides! So
snd . head . filter (\(k,v) -> key == k) $ xs
is effectively
( snd . head . filter (\(k,v) -> key == k) ) ( xs )
Of course, the parens around xs are unneeded here (that's an "atom" anyway), so the relevant ones are in this case around the left side. Indeed that happens often in Haskell, because the general philosophy is to think about functions as abstract entities as much as possible, rather than the particular values involved when applying the function to some argument. Your definition could also be written
let findKey key xs' = let filter (\(k,v) -> key == k) $ xs
x0 = head xs'
v0 = snd x0
in v0
That would be extremely explicit, but all those intermediate values aren't really interesting. So we prefer to simply chain the functions together "point-free", with .. That often gets us rid of a lot of boilerplate, indeed for your definition the following can be done:
η-reduction of the xs. That argument just passed on to the chain of functions, so we might as well say "findKey key" is that chain, with whatever argument you supply"!
findKey key = snd . head . filter (\(k,v) -> key == k)
Next, we can avoid this explicit lambda: \(k,v) -> k is simply the fst function. You then need to postcompose comparison with key.
findKey key = snd . head . filter ((key==) . fst)
I'd stop here, since too much point-free is pointless and unreadable. But you could go on: there's new parens now around the argument to key, we can again get rid of those with $. But careful:
"findKey key = snd . head . filter $ (key==) . fst"
is not right, because the $ would again parenthesise both sides, yet (snd . head . filter) is not well-typed. Actually snd . head should only come after both arguments to filter. A possible way to do such a post-post-composition is using the function functor:
findKey key = fmap (snd . head) . filter $ (key==) . fst
...we could go on even further and get rid also of the key variable, but it wouldn't look nice. I think you've got the point...
Other answers have commented in detail on how ($) can replace parentheses, since ($) was defined as an application operator with the right precedence.
I'd like to add that GHC, in order to make it possible to replace parentheses with ($), uses some more magic under the hood than what can be seen from the definition of ($). When higher rank functions are involved, the type system can cope with higher-rank arguments when passed through standard application (as in f x), but not when passed though an application operator (as in f $ x). To overcome this problem, GHC handles ($) in a special way in the type system. Indeed, the following code shows that if we define and use our own application operator ($$), the type system does not apply the same magic handling.
{-# LANGUAGE RankNTypes #-}
-- A higher rank function
higherRank :: (forall a. a -> a -> a) -> (Int, Char)
higherRank f = (f 3 4, f 'a' 'b')
-- Standard application
test0 :: (Int, Char)
test0 = higherRank const -- evaluates to (3,'a')
-- Application via the ($) operator
test1 :: (Int, Char)
test1 = higherRank $ const -- again (3, 'a')
-- A redefinition of ($)
infixr 0 $$
($$) :: (a -> b) -> a -> b
($$) = ($)
test2 :: (Int, Char)
test2 = higherRank $$ const -- Type error (!)
-- Couldn't match expected type `forall a. a -> a -> a'
-- with actual type `a0 -> b0 -> a0'
I have just began recently to learn Haskell, more specifically on the topics of function composition, partial functions, maps, filters and sectioning. On one of the exercises am asked to modify the twoFilters function by using function composition.
I have read a few wikis on . but am having quite a hard time getting it to work correctly. As i understand it, it works by performing the functions b . a on alphabetical order and returning the result. In other words x = foo a and then foo b of x. However after applying several "variations/possibilities" with the bellow two filters functions i cant get it to compile due to errors.
greaterThanOne :: Int -> Bool
greaterThanOne = (>1)
lessThanTen :: Int -> Bool
lessThanTen = (<10)
twoFilters :: [Int] -> [Int]
twoFilters xs= filter lessThanTen (filter greaterThanOne xs)
These two being the unsuccessful attempts I had most confidence on;
twoFilters xs = filter (lessThanTen . greaterThanOne xs)
twoFilters xs = filter (lessThanTen xs . greaterThanOne xs)
Where on the reasoning am I going wrong?
The attempts you were confident about are a simple failure in your logic: the dot operator works like this:
(f.g)(x) = f(g(x))
So, trying to compute an example of 5 gives:
lessThanThen(greaterThanOne(5)) = lessThanTen(True) -- that can't be right, can it???
What you want is a lambda and &&:
filter (\x-> (lessThanThen x) && greaterThanOne(x))
Alternatively, you can use two filters:
filter lessThanTen . filter greaterThanOne $
Enter the wonderful world of Applicative Functors:
import Control.Applicative
greaterThanOne = (>1)
lessThanTen = (<10)
twoFilters = filter ((&&) <$> greaterThanOne <*> lessThanTen)
twoFilters [1,2,3,4,5,6,7,8,9,10]
-- [2,3,4,5,6,7,8,9]
Read Learn you a Haskell - Applicative Functors for a detailed explanation.
You can't compose those two functions like this. f . g works like composition in maths, i.e. is equivalent to f(g(x)). That means the outer function must take an argument of a type that inner function returns, in your case the outer function would have to be Bool -> Bool.
You can write your twoFilters using composition operator like this:
twoFilters = (filter lessThanTen) . (filter greaterThanOne)
(.) expects a function which takes one argument and returns a value, but you pass it a Bool value in:
lessThanTen . greaterThanOne xs
which is wrong.
Here:
lessThanTen xs . greaterThanOne xs
you're trying to compose two Bool values, but you should've composed two functions which return Bool values.
One issue it that function application has highest precedence. So lessThanTen . greaterThanOne xs tries to compose lessThanTen with the result of greaterThanOne xs (which doesn't work to start with, the function works on integers, not on lists thereof). Likewise, lessThanTen xs. greaterThanOne xs tries to compose the results of those function calls (assuming they'd make sense in the first place), not the functions themself.
Another problem is a misunderstanding of . - (f . g) x is equivalent to f (g x), i.e. the result of the first function is the argument for the second. So the type of g must be (a -> b) and the type of f must be (b -> c) (both b are the same type variable!). What you want to apply both functions to the same argument and join the results with &&. There's no existing functions for this as far as I know (at least Hoogle didn't find anything for (a -> Bool) -> (a -> Bool) -> a -> Bool). You'll have to make your own:
both f g x = f x && g x
Alternatively, you coudl just stick to filtering twice (which isn't as bad as it sounds thanks to lazy evaluation) - filter (>1) $ filter (<10) xs.
As i understand it, it works by performing the functions b . a on alphabetical order and returning the result. In other words x = foo a and then foo b of x
This could be written in Haskell as
let x = foo a in
foo b x
(where does foo come from?) but the correct
(b . a) x = let y = a x in
b y
Or, shorter:
(b . a) x = b (a x)
Now, filter lessThanTen (filter greaterThanOne xs) has a similar shape to the right side of this definition, if you remember you could write it as (filter lessThanTen) ((filter greaterThanOne) xs):
((filter lessThanTen) . (filter greaterThanOne)) xs
Presumably what you actually want is filter ??? xs, but that should be enough to go on with.
You have it almost right. I find the easiest way to start learning function composition with . is to use $ first instead.
So you have a list
twoFilters xs = xs
You want to filter by greaterThanOne
twoFilters xs = filter greaterThanOne $ xs
You additionally want to filter by lessThanTen
twoFilters xs = filter lessThanTen $ filter greaterThanOne $ xs
Now move from left to right, replacing all $s with . except for the last $
twoFilters xs = filter lessThanTen . filter greaterThanOne $ xs
You could use parenthesis instead of $ now:
twoFilters xs = (filter lessThanTen . filter greaterThanOne) xs
Or just define the function pointfree:
twoFilters = filter lessThanTen . filter greaterThanOne
The parenthesized version is the most important, I think. It shows that you fuse the two partially-applied functions filter lessThanTen and filter greaterThanOne into one mega-filtering function, with . and then you apply the list to it. You need to parenthesize them because . binds less tightly than function application via whitespace (space can be considered an uber-high-fixity version of $). Remember, when you use ., you are fusing two functions together to form one mega-function.
It is relevant to inspect the type signature of .
(.) :: (b -> c) -> (a -> b) -> a -> c
The functions you feed it have to "line up" with very particular type signatures (they have to be compatible for fusing). But honestly, the key is learning to recognize when function application (with space) is binding more tightly than you intend and messing up the type signatures of functions you are trying to compose. That's how it was for me, anyways.