Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a typo in a Haskell function declaration cause GHCi to throw errors around previously compiling code?

Tags:

haskell

ghci

Here's sort of a weird question. Learning Haskell through LearnYouaHaskell, great book btw, and I'm going through implementing various examples.

This compiles in GHCi

cylinder :: (RealFloat a) => a -> a -> a
cylinder r h =
    let sideArea = 2 * pi * r * h
    topArea = pi * r ^2
    in  sideArea + 2 * topArea

This compiles in GHCi

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]  
zipWith' _ [] _ = []  
zipWith' _ _ [] = []  
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys 

If I intentionally make a typo and declare the second function as so

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]  
zipWith' _ [] _ = []  
zipWith' _ _ [] = []  
zipWith' f (x:xs) (y:ys) = f xs y : zipWith' f xs ys 

Then the first and second function throw errors during compilation - at least that's what I think is happening.

Sorry in advance for the code dump.

It throws this previously unseen error message about the cylinder function which I did not change

Prelude> :l functions2.hs
[1 of 1] Compiling Main             ( functions2.hs, interpreted )

functions2.hs:4:26:
    Could not deduce (Integral b0) arising from a use of ‘^’
    from the context (RealFloat a)
      bound by the type signature for
                 cylinder :: RealFloat a => a -> a -> a
      at functions2.hs:1:13-40
    The type variable ‘b0’ is ambiguous
    Note: there are several potential instances:
      instance Integral Int -- Defined in ‘GHC.Real’
      instance Integral Integer -- Defined in ‘GHC.Real’
      instance Integral GHC.Types.Word -- Defined in ‘GHC.Real’
    In the second argument of ‘(*)’, namely ‘r ^ 2’
    In the expression: pi * r ^ 2
    In an equation for ‘topArea’: topArea = pi * r ^ 2

functions2.hs:4:27:
    Could not deduce (Num b0) arising from the literal ‘2’
    from the context (RealFloat a)
      bound by the type signature for
                 cylinder :: RealFloat a => a -> a -> a
      at functions2.hs:1:13-40
    The type variable ‘b0’ is ambiguous
    Note: there are several potential instances:
      instance Num Double -- Defined in ‘GHC.Float’
      instance Num Float -- Defined in ‘GHC.Float’
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus three others
    In the second argument of ‘(^)’, namely ‘2’
    In the second argument of ‘(*)’, namely ‘r ^ 2’
    In the expression: pi * r ^ 2

As well as this much more reasonable error message about the typo in the second function

functions2.hs:12:30:
    Couldn't match expected type ‘a’ with actual type ‘[a]’
      ‘a’ is a rigid type variable bound by
          the type signature for
            zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
          at functions2.hs:9:13
    Relevant bindings include
      xs :: [a] (bound at functions2.hs:12:15)
      x :: a (bound at functions2.hs:12:13)
      f :: a -> b -> c (bound at functions2.hs:12:10)
      zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
        (bound at functions2.hs:10:1)
    In the first argument of ‘f’, namely ‘xs’
    In the first argument of ‘(:)’, namely ‘f xs y’
Failed, modules loaded: none. 

Why? Is this a common bug? Did I break something in the first by ruining the second? Please advise.

like image 374
Joe Susnick Avatar asked Jul 04 '15 19:07

Joe Susnick


People also ask

How does GHCi work?

GHCi will discover which modules are required, directly or indirectly, by the topmost module, and load them all in dependency order. If you started up GHCi from the command line then GHCi's current directory is the same as the current directory of the shell from which it was started.

What is the difference between GHC and GHCi?

Introduction. GHCi is GHC's interactive environment, in which Haskell expressions can be interactively evaluated and programs can be interpreted.

How do I load a Haskell file into GHCi?

Open a command window and navigate to the directory where you want to keep your Haskell source files. Run Haskell by typing ghci or ghci MyFile. hs. (The "i" in "GHCi" stands for "interactive", as opposed to compiling and producing an executable file.)

What does variable not in scope mean in Haskell?

(When GHC complains that a variable or function is "not in scope," it simply means that it has not yet seen a definition of it yet. As was mentioned before, GHC requires that variables and functions be defined before they are used.)


1 Answers

This was GHC bug ticket #9033, reported in April 2014 and quickly fixed.

Basically, whenever a file contained almost any type error, GHC would skip the type class defaulting step, which could cause other parts of the file to give spurious ambiguous type errors.

As @leftaroundabout notes, the ^ operator is a frequent trigger of this, since its second argument type is unconnected with the other types and so very often needs defaulting.

The GHC version listed in the ticket is 7.8.2, and 7.8.3 was released in July 2104, so I assume versions 7.8.3 and later have the fix.

like image 192
Ørjan Johansen Avatar answered Dec 04 '22 19:12

Ørjan Johansen