I made this function
replace :: Char -> Char -> [Char] -> [Char]
replace _ _ [] = []
replace a b (c:r)
| a == c = b : replace a b r
| otherwise = c : replace a b r
and was looking for a better way to write it when i found this :
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map $ \c -> if c == a then b else c
There not even the third argument written, and i don't understand the $ and the \c symbols, but it work and I want to know what is happening here
The $ operator applies a function to an argument. We can rewrite your example as
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map (\c -> if c == a then b else c)
Pragmatically, Haskellers often use $ to avoid parentheses. It's rarely used for other reasons.
About the \c -> ...: this is an anonymous function, also called a "lambda". It stands for the function taking c as argument and returning the ... part. In your case, the function takes c and checks if it's equal to a, in which case it returns b, otherwise it returns c. We could rewrite the code without the lambda as follows:
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where
myFun :: Char -> Char
myFun = \c -> if c == a then b else c
or, moving the argument c to the left of =, as follows:
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where
myFun :: Char -> Char
myFun c = if c == a then b else c
About the "missing third argument": the type Char -> Char -> [Char] -> [Char] can be read in multiple ways:
Char) and returning a function (Char -> [Char] -> [Char])Char and Char) and returning a function ([Char] -> [Char])Char, Char, and [Char]) and returning a list ([Char])All these three interpretations are compatible, thanks to currying. Indeed, the "two arguments" function
foo :: A -> B -> B
foo x y = y
and the function
foo :: A -> B -> B
foo x = id -- id is the identity function B -> B
are the same.
In your example, if you want, you can add the missing argument to both sides of = as follows:
replace :: Char -> Char -> [Char] -> [Char]
replace a b xs = map myFun xs
where
myFun :: Char -> Char
myFun c = if c == a then b else c
In this expanded code, you can see that map myFun xs uses map (library function) to apply myFun to all the elements of list xs, and return the list of all the results.
This effectively achieves the substitution you want.
However, without adding the third argument,
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where ...
we can still interpret map myFun as transforming the function myFun :: Char -> Char into a function [Char] -> [Char]. The latter is indeed the return type of replace if we interpret that as a "two arguments" function. That is, replace 'a' 'b' is the function [Char] -> [Char] which takes a string and replaces every 'a' in it with a 'b'.
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