Why is my Haskell code saying 'variable not in scope: main'?
Asked Answered
S

4

21

When I type the following in the interactive shell of Haskell on the repl.it website, it works perfectly.

let squareMe x = x * x
let myFruit = ["banana", "apple", "kiwi", "orange"]

But when I type it into a source file and click 'Run' I get the error:

<interactive>:3:1: error:
    • Variable not in scope: main
    • Perhaps you meant ‘min’ (imported from Prelude)

I've been trying to understand this error and come up with a solution for a couple of hours now and am no nearer to finding a solution or understanding what the error means.

Swane answered 3/10, 2017 at 14:37 Comment(3)
A program requires an entry point: a monadic function called main.Gird
What you wrote is not really correct. The code isn't complete (I miss main). Also, please check let it be. I suggest to read that book from start.Pester
main :: IO () main = putStrLn "Hello, World" I've entered the simplest code. and it is saying: error: Variable not in scope: main :: IO a0 Suggested fix: Perhaps use `min' (imported from Prelude) maybe the problem is again with the syntax difference between he Haskell REPL (GHCi) and actual Haskell programs!!?Selfrespect
V
28

The Haskell REPL (GHCi) and actual Haskell programs are considerably different.

The reasons for this difference is the goal of the two formats. Firstly, GHCi is a testing area, not a code-running area. However, Haskell source files are meant to run a certain process, which is named main. When you run a source file, the Haskell compiler (usually GHC) looks for the IO action called main, and tries to run it. In this case, there was no main, so it failed.

Secondly, what you typed is not a valid Haskell program, those are declarations that would be fine in GHCi, but not in Haskell source. This would be correct in a source file:

squareMe x = x * x

myFruit = ["banana", "apple", "kiwi", "orange"]

Note the lack of let; Haskell source files don't use it to declare things.

Note that on repl.it, this will still complain that main is missing, but you can then refer to squareMe and myFruit in the REPL without worry. In other words, the error will still appear, but it doesn't matter, because you can use whatever you wrote in the file nonetheless.

If you wanted to suppress the warning, you could write the lines:

main :: IO ()    -- This says that main is an IO action.
main = return () -- This tells main to do nothing.

There are many things you could have the program do instead of this. Here are a couple of examples:

  • main = putStrLn "No errors!" Will print No errors! when you run it.
  • main = print myFruit Will print ["banana", "apple", "kiwi", "orange"] when you run it.

Please note that this answer applies mostly to the site repl.it specifically, though in general this is how Haskell programs are structured.

Vernita answered 3/10, 2017 at 15:41 Comment(1)
main :: IO () main = putStrLn "Hello, World" I've entered the simplest code. and it is saying: error: Variable not in scope: main :: IO a0 Suggested fix: Perhaps use `min' (imported from Prelude) maybe the problem is again with the syntax difference between he Haskell REPL (GHCi) and actual Haskell programs!!?Selfrespect
D
9

If you compile a Haskell source there needs to be a main symbol as entry point, just like when compiling e.g. a C program. Also in a compiled file you must skip the lets. E.g.

squareMe x = x * x

main = putStrLn . show $ squareMe 4
Dismember answered 3/10, 2017 at 15:7 Comment(5)
There's no need to use show within print: that is already polymorphic on the input type.Nonconductor
print x = putStrLn (show x), so your code calls show twice.Crackpot
@leftaroundabout, indeed. print probably shouldn't even be in the prelude, since it becomes the wrong function as soon as you want to piece together output from multiple values, or add newlines, or whatever. print = putStrLn . show, readLn = readIO =<< getLine, and neither of these convenience functions seems worth the didactic overhead.Lauder
@Lauder I find print too handy to agree with that. In fact I'd be more inclined to say Show and Read shouldn't be in the prelude. (One should very seldom feel the need to convert anything to/from string, except for the purpose of doing IO with those strings.)Nonconductor
Thanks, edited the answer and replaced the print with putStrLn.Dismember
L
1

If what you’re writing is more like a library or a set of utility routines than a complete program, you can declare it as a module. Then GHC will compile it to an object you can link to other programs, and you can also load it in GHCI. It will not be expected to contain a main routine.

If you save this to a .hs file:

module Example (squareMe) where

squareMe x = x * x -- Exported to other modules.
myFruit = ["banana", "apple", "kiwi", "orange"] -- Not exported.

Compiling this with GHC will give you a .hi file and a .o file, and running it in GHCI will give you this:

GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Ok, modules loaded: Example (sx-modulexmpl.o).
Prelude Example> squareMe 2
4

You can also compute an expression that references a library from the command line. ghc -e "squareMe 2" Example.hs prints 4.

Lingerfelt answered 3/10, 2017 at 18:39 Comment(0)
B
-1

Open a file in a text editor and save it as somecode.hs.

In somecode.hs:

main = do
  let squareMe x = x * x
  let myFruit = ["banana", "apple", "kiwi", "orange"]

Save it and run it in the terminal as:

runghc somecode.hs
Bs answered 25/5, 2024 at 12:55 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.