Why can't I use undefined just everywhere?

Viewed 139

I thought I could always put undefined in same place where I don't know yet what to put, and the code should compile fine, the error happening at run time only if that undefined is actually eveluated.

However, just in doing so I started writing something like

f = foldl undefined undefined undefined

in a file, and GHCi gives this error when I try to load the file

source.hs:3:7: error:
    • Ambiguous type variable ‘t0’ arising from a use of ‘foldl’
      prevents the constraint ‘(Foldable t0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘t0’ should be.
      These potential instances exist:
        instance Foldable (Either a) -- Defined in ‘Data.Foldable’
        instance Foldable Maybe -- Defined in ‘Data.Foldable’
        instance Foldable ((,) a) -- Defined in ‘Data.Foldable’
        ...plus one other
        ...plus 29 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: foldl undefined undefined undefined
      In an equation for ‘f’: f = foldl undefined undefined undefined
  |
3 | f = foldl undefined undefined undefined
  |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Which I interpret as "undefined does not typecheck here".

What is the rational behind this behavior, and what are the places where I cannot use undefined as a temporary placeholder?

1 Answers

The interpreter does not know what type for f in foldl :: Foldable f => (a -> b -> a) -> a -> f b -> a to use, hence the error. This is important since the f here decides exactly what implementation for foldl it will use. Indeed for a f ~ Maybe the implementation can be different than for an f ~ [], so depending on the type for f, a different foldl is used.

If we specify the type, for example with [Int], or Maybe Char, this works (well it will raise an error, but this is because the undefined will of course not evaluate properly):

Prelude> foldl undefined undefined (undefined :: Maybe Char)
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:78:14 in base:GHC.Err
  undefined, called at <interactive>:1:6 in interactive:Ghci1
Prelude> foldl undefined undefined (undefined :: [Int])
*** Exception: Prelude.undefined
CallStack (from HasCallStack):
  error, called at libraries/base/GHC/Err.hs:78:14 in base:GHC.Err
  undefined, called at <interactive>:2:6 in interactive:Ghci1

For certain type classes like Num, there is type defaulting [Wkang's Haskell; blog]. This uses:

default Num Integer
default Real Integer
default Enum Integer
default Integral Integer
default Fractional Double
default RealFrac Double
default Floating Double
default RealFloat Double
Related