Skip to content

ghci scripts ending in printf lines fail with Exception: Prelude.undefined

There appears to be some differences in runhaskell/ghci and ghc when it comes to printf.

Consider this program:

import Text.Printf
import System.Environment

main = do
    [who] <- getArgs
    printf "hello, %s\n" who

when compiled:

$ ghc A.hs
$ ./A world
hello, world

When run in GHci:

$ ghci A.hs
Prelude Main> :set args world
Prelude Main> main
hello, world
*** Exception: Prelude.undefined

Hmm! And in runhaskell:

$ runhaskell A.hs world
hello, world
*** Exception: Prelude.undefined

An ugly 'return ()' seems to help:

import Text.Printf
import System.Environment

main = do
    [who] <- getArgs
    printf "hello, %s\n" who
    return ()

which produces:

$ runhaskell A.hs world
hello, world

As does an explicit annotation:

$ cat A.hs
import Text.Printf
import System.Environment

main = do
    [who] <- getArgs
    printf "hello, %s\n" who :: IO ()

So some defaulting is coming into play?

$ ghci
Prelude> :l A.hs
*Main> :t main
main :: IO t

*Main> :set args world
*Main> main :: IO ()
hello, world

*Main> main :: IO String
hello, world
"*** Exception: Prelude.undefined

Is GHCi/runhaskell giving an overly generous type to 'main'? I note the following is also valid "runhaskell" programs:

$ cat A.hs
main = return "hello, world"

$ runhaskell A.hs
"hello, world"
Trac metadata
Trac field Value
Version 6.6
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component GHCi
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system Unknown
Architecture Unknown
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information