I am trying to refactor a mapM_
function call inside a do
block in Haskell. I would like to extract the lambda to a (locally) named function to make the code more readable.
My code originally looks like this:
do -- ... mapM_ (\x -> x + 1) aList return aValue
I would like to change it to
do -- ... mapM_ func aList where func x = x + 1 return aValue
but I am getting a syntax error on the return aValue
line. My actual lambda is more complicated :-), but I did try it with this same lambda to make sure it was not an issue in the lambda code.
How can I rewrite this code? Should I use let
... in
instead?
in goes along with let to name one or more local expressions in a pure function.
Definition on Haskell Where Function. Haskell where is not a function rather it is a keyword that is used to divide the more complex logic or calculation into smaller parts, which makes the logic or calculation easy to understand and handle.
() is very often used as the result of something that has no interesting result. For example, an IO action that is supposed to perform some I/O and terminate without producing a result will typically have type IO () .
It lets you write something resembling the sequential statements of an imperative language, but then it desugars to function applications. Everything you can write in do-notation, you can write (sometimes less clearly) with regular function application.
There are three similar (but distinct) ways of defining stuff here:
You can attach where
clauses after certain definitions--mostly equation-style bindings. So you could put one at the end of your function, or after something defined with let
or a surrounding where
clause.
On the other hand, let x = ... in ...
is an expression that evaluates to the part after in
, which is the only place the stuff after let
is visible.
Inside a do
block, because there's already an implicit nesting of scope (things are visible after they're first defined), you can use just let x = ...
alone. This is really the same thing as the previous form--the rest of the do
block after the let
is effectively the in ...
portion.
If you want a local definition that uses something defined within the do
block, your only choice is the third (or passing the other value(s) as argument(s)). For an independent helper functions like your example, however, any style works. Here's your example, to demonstrate each:
The first style, where func
is visible anywhere in foo
, including anything else defined in the where
clause:
foo = do ... mapM_ func aList ... return aValue where func x = x + 1
The second style, where func
is only visible inside the let
expression, which in this case is the entire do
block:
foo = let func x = x + 1 in do ... mapM_ func aList ... return aValue
And the third style, defining it inside the do
block. In this case, func
is only visible after the let
; in the first ...
it hasn't been defined yet.
foo = do ... let func x = x + 1 mapM_ func aList ... return aValue
Oh, and for good measure: Since let ... in ...
is an expression, you can also use it anywhere you have an expression, to name some local definitions. So here's another example:
foo = do ... let func x = x + 1 in mapM_ func aList ... return aValue
As before, func
is only visible inside the let
expression, which in this case is the single expression after it, nowhere else.
Another option is to use forM_
instead of mapM_
, which flips the order of the arguments. You can then use the $
operator with a trailing lambda expression like this:
do forM_ aList $ \x -> do ... return aValue
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