2

If I define

data Thing = Shoe
           | Ship
           | SealingWax
           | Cabbage
           | King

and then in a later cell in an IHaskell Notebook enter

thing :: Thing
thing = 4

I get an error ("No instance for (Num Thing) arising from the literal ‘4’") as expected. But if I first complete a valid binding with

thing :: Thing
thing = King

and then later, in a separate cell make the same (invalid) assignment with

thing = 4

I get no error, and t: thing yields thing :: (Num a) => a.

More perplexingly, if I put

thing = Cabbage
:t thing
thing = 5
:t thing

in a single cell I get no errors and

thing :: Thing
thing :: (Num a) => a

but a single cell without the :t lines

thing = Cabbage
thing = 5

gives an error:

Multiple declarations of ‘thing’
Declared at: :1:1
             :2:1

Why can I change the type of a variable in separate IHaskell Notebook cells?

orome
  • 45,163
  • 57
  • 202
  • 418

1 Answers1

5

In Haskell, you can't change or reassign variables. What you're doing is declaring a new variable that just reuses the name shoe, but is otherwise entirely distinct.

Your second definition of show shadows the first because it takes the same name, but it doesn't affect it in any other way.

The single-cell example is a bit more confusing: essentially, a :t separates the cell into multiple definitions. With the :t, it's as if you had two cells; without it, it's as if you simultaneously tried to define x in two different ways—which wouldn't have worked even if they had the same type.

In general, shadowing names in Haskell is a bit awkward and not good style. You can even enable a warning about it:

:set -fwarn-name-shadowing

It can also be turned on as part of a larger suite of warnings:

:set -Wall
Tikhon Jelvis
  • 67,485
  • 18
  • 177
  • 214
  • So perhaps the question then is why I'm prevented from shadowing in some cases and allowed in others (see edit above) . – orome Aug 19 '15 at 18:09
  • And: Is there way to configure Haskell to warn about shadowing? – orome Aug 19 '15 at 18:10
  • 1
    @raxacoricofallapatorius: Yep. I was about to add that to my answer :). You can turn on the `-fwarn-name-shadowing` flag: `:set -fwarn-name-shadowing`. That works from `ghci` for sure and *probably* works from IHaskell, but I don't have it running locally to test. – Tikhon Jelvis Aug 19 '15 at 18:11
  • Cool. I'll see if I can set up IHaskell to do that (maybe a new question). – orome Aug 19 '15 at 18:15
  • So, to be clear: What looks like (coming from other languages) *assignment* is in fact *definition*? Doing `thing = 5` after `thing = King` doesn't attempt to assign `5` to the existing `thing` but creates something new? If so, what about `thing = Ship` after `thing = King`? – orome Aug 19 '15 at 18:17
  • @raxacoricofallapatorius: Yep, it's always definition, never assignment. It's a bit less obvious in a setting like IHaskell because the normally static change of defining a new value with the same name happens interactively. – Tikhon Jelvis Aug 19 '15 at 18:22
  • And that's true even if the types match (as in `thing = Ship` after `thing = King`): `King` is still around, just shadowed by `Ship`, right? – orome Aug 19 '15 at 18:23
  • 1
    @raxacoricofallapatorius: Yep. It would be inconsistent otherwise. – Tikhon Jelvis Aug 19 '15 at 18:28