Haskell where clause syntax inside a do block

感情迁移 提交于 2019-12-03 16:08:42

问题


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?


回答1:


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.




回答2:


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



回答3:


Shouldn't your where be at the end of the function?

Like this:

function aList aValue = do
    mapM_ func aList
    return aValue
    where func x = x + 1


来源:https://stackoverflow.com/questions/14092801/haskell-where-clause-syntax-inside-a-do-block

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!