When you are writing slightly more complex functions I notice that $
is used a lot but I don't have a clue what it does?
The @ Symbol is used to both give a name to a parameter and match that parameter against a pattern that follows the @ . It's not specific to lists and can also be used with other data structures.
(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.
It's merely an infix synonym for fmap , so you can write e.g. Prelude> (*2) <$> [1.. 3] [2,4,6] Prelude> show <$> Just 11 Just "11" Like most infix functions, it is not built-in syntax, just a function definition. But functors are such a fundamental tool that <$> is found pretty much everywhere.
in goes along with let to name one or more local expressions in a pure function.
$
is infix "application". It's defined as
($) :: (a -> b) -> (a -> b) f $ x = f x -- or ($) f x = f x -- or ($) = id
It's useful for avoiding extra parentheses: f (g x) == f $ g x
.
A particularly useful location for it is for a "trailing lambda body" like
forM_ [1..10] $ \i -> do l <- readLine replicateM_ i $ print l
compared to
forM_ [1..10] (\i -> do l <- readLine replicateM_ i (print l) )
Or, trickily, it shows up sectioned sometimes when expressing "apply this argument to whatever function"
applyArg :: a -> (a -> b) -> b applyArg x = ($ x) >>> map ($ 10) [(+1), (+2), (+3)] [11, 12, 13]
I like to think of the $ sign as a replacement for parenthesis.
For example, the following expression:
take 1 $ filter even [1..10] -- = [2]
What happens if we don't put the $? Then we would get
take 1 filter even [1..10]
and the compiler would now complain, because it would think we're trying to apply 4 arguments to the take
function, with the arguments being 1 :: Int
, filter :: (a -> Bool) -> [a] -> [a]
, even :: Integral a => a -> Bool
, [1..10] :: [Int]
.
This is obviously incorrect. So what can we do instead? Well, we could put parenthesis around our expression:
(take 1) (filter even [1..10])
This would now reduce to:
(take 1) ([2,4,6,8,10])
which then becomes:
take 1 [2,4,6,8,10]
But we don't always want to be writing parenthesis, especially when functions start getting nested in each other. An alternative is to place the $
sign between where the pair of parenthesis would go, which in this case would be:
take 1 $ filter even [1..10]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With