Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: Can I use a where clause after a block with bind operators (>>=)?

I have a very simple question. I'd like to use a where clause after a bloc of code that uses bind operators but I get a compilation error.

Here is a simple example:

main =
    putStrLn "where clause test:" >>
    return [1..10] >>= \list ->
    print list'
        where list' = reverse list -- test1.hs:5:28: Not in scope: `list'

I can use a let clause for list' as in

main =
    putStrLn "where clause test:" >>
    return [1..10] >>= \list ->
    let list' = reverse list -- works of course
    in print list'

but I'd really like it if I could use a where clause...

I also tried with do notation

main = do
    putStrLn "where clause test:"
    list <- return [1..10]
    print list'
        where list' = reverse list --test3.hs:5:30: Not in scope: `list'

Same problem. Can I use a where clause in these circumstances?

like image 886
Fred Dubois Avatar asked Jul 21 '09 02:07

Fred Dubois


1 Answers

As ephemient explains, you can't use where clauses the way you do.

The error happens because in this code:

main =
  return [1..10] >>= \list ->
  print list'
    where
      list' = reverse list

The where-clause is attached to the main function.

Here's that same function with more parentheses:

main = return [1..10] >>= (\list -> print list')
  where
    list' = reverse list

I think its fairly obvious why you get the "out of scope" error: The binding for list is deep inside the main expression, not something the where clause can reach.

What I usually do in this situation (and I've been bitten by the same thing a bunch of times). I simply introduce a function and pass the list as an argument.

main = do
  list <- return [1..10]
  let list' = f list
  print list'
  where
    f list = reverse list -- Consider renaming list,
                          -- or writing in point-free style

Of course, I imagine your actual code in the f function is a lot more that just reverse and that's why you want it inside a where clause, instead of an inline let binding. If the code inside the f function is very small, I'd just write it inside the let binding, and wouldn't go through the overhead of introducing a new function.

like image 108
Tom Lokhorst Avatar answered Sep 21 '22 06:09

Tom Lokhorst