If we want to map a function that increases every element of a range by 1, we could write
map (\x -> x + 1) [1..5]
but I guess most people would just go for
map (+1) [1..5]
instead. But this obviously doesn't work with (-1) since that's negative one.
So the first thing that came to mind was
map (+(-1)) [1..5]
which would make sense considering how subtraction is defined in the Prelude (x - y = x + negate y
), but looks a bit odd to me. I then I came up with
map (flip (-) 1) [1..5]
This somehow looks better to me, but is maybe a bit too complicated.
Now I know this no big deal, but I'm wondering if I'm missing a more obvious way to write this? If not, which of the 2 ways would you prefer? I'm really just asking because often it's small details like this that make your code more idiomatic and hence pleasant for other developers who have to read it.
Solution
Now that I got a couple of answers, I think my personal favorite is
map (subtract 1) [1..5]
followed by
map pred [1..5]
mostly because the first one is really explicit and nobody needs to guess/look up what pred
means (predecessor).
You can use the subtract
function instead of -
if you want to right-section subtraction:
map (subtract 1) [1..5]
Since -
is both the infix subtract and the prefix negate, you can't use the (*x)
(where * is an infix operator and x a value) syntax for -
. Luckily Prelude comes with negate
and subtract
, which is \x -> -x
and \x y -> y-x
respectively, so that you may use those where you need to differentiate between the two.
I think map (\x -> x - 1) [1..5]
transmits the programmer's intention better, since there's no doubt about what is being subtracted from what. I also find your first solution, map (+(-1)) [1..5]
, easy to read too.
I don't like subtract
because it's confusingly backwards. I'd suggest
minus :: Num n => n -> n -> n
minus = (-)
infixl 6 `minus`
Then you can write
map (`minus` 1) [1..5]
After many years since this question was asked, in GHC 9 we now have
the LexicalNegation
extension which allows the section (- 1)
, as long we use whitespace to separate the minus sign from the number.
Indeed, after enabling the extension, we have:
> map (subtract 1) [1..5] -- still works, of course
[0, 1, 2, 3, 4]
> map (- 1) [1..5] -- with whitespace
[0, 1, 2, 3, 4] -- (- 1) is now a section
> map (-1) [1..5] -- no whitespace
*error* -- (-1) is now a negative literal
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