Functor
Functor

Reputation: 610

Block scope in Haskell?

I've found block scope {and } in JavaSciprt after ES6 is useful in development, and frequently use for testing small code blocks including the same variable names in different versions side by side.

How do you do in Haskell? What's the best prctice?

Upvotes: 1

Views: 197

Answers (2)

Daniel Wagner
Daniel Wagner

Reputation: 152682

There's a few choices, depending on what context you're looking for. I think the thing most likely to be useful to you is that each binding can be associated with a where block, and the variables in each block are independent. So, for example:

foo = component1 * component2 where
    component1 = x + y where
        x = 32
        y = sqrt (magnitude velocity)
    component2 = x + y where
        x = magnitude acceleration
        y = 5.5

In each case, the x and y are in scope only for the component that's currently being defined.

One place that doesn't always work well is in do blocks. There's two reasons for this: first, the associated where block's scope doesn't include any of the variables bound by statements in the do block, and second, because sometimes the thing you want is differing scopes for differing parts of the do block. For those cases, let/in works better. For example:

foo = do
    let x = print "hi"
        y = putStrLn "hi"
    in do
        x
        y
    -- x and y are no longer in scope here
    v <- readLn :: IO Int
    let x = print [v] -- v is in scope, unlike a where block
        y = print v
    in do
        x
        y

Again, in each case, the x and y are in scope for the body of the nested do block, but not in scope in the outer do block. It is also possible to add something to the outer do block's scope, though of course the syntax has to be different (or how would the compiler know which one you wanted?). The difference is that you leave off the in, so:

foo = do
    v <- readLn :: IO Int
    let w = v + v
    print w

Upvotes: 2

Noughtmare
Noughtmare

Reputation: 10645

If you have some code like this:

foo x y = do
  print x
  print y

And you want to temporarily test changing the value of x then you can just write:

foo x y = let x = 2 in do
  print x
  print y

This let syntax creates a new scope and "overwrites" (shadows) any variables with the same name that were previously bound. You can use this let almost everywhere, e.g.:

foo x y = do
  let x = 2 in print x
  print y

Or even:

foo x y = do
  print (let x = 2 in x)
  print y

It is really flexible.

Upvotes: 4

Related Questions