Search code examples
haskellfunctional-programmingconstraintstypechecking

Why can't I use undefined just everywhere?


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?


Solution

  • 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