Search code examples
haskelltypescastingihaskell

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


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?


Solution

  • 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