Haskell modules: hidden names and ghci - haskell

I'm trying to export just a subset of names from a Haskell module, but ghci happily lets me access even the hidden names.
module Hiding (shown, calc) where
calc = shown * hidden
shown :: Int
shown = 3
hidden :: Int
hidden = 2
But when trying this in ghci I get:
Prelude> :l Hiding.hs
[1 of 1] Compiling Hiding ( Hiding.hs, interpreted )
Ok, modules loaded: Hiding.
*Hiding> hidden
2
What am I doing wrong?
(Edit: for what it's worth, I'm using ghci 6.12.3 on Arch Linux)

It looks like GHCi is loading your module for you to inspect it, i.e. putting you in the scope of the module. Two hints at that are the prompt *Hiding> and the fact that you accessed the hidden function.
Edit:
End there it is: http://www.haskell.org/ghc/docs/latest/html/users_guide/interactive-evaluation.html#id3045728

It looks to me like you've done the right thing. If you attempt to reference that module from another module I'll bet hidden refuses to work. Could be that GHCI is all-knowing :)

Related

Haskell: Parse error: module header, import declaration or top-level declaration expected

I am saving some commands in a Haskell script in a .hs file while working thru a Haskell textbook. Here's a small example.
fst (1,2)
snd (1,2)
When I run these commands from the prelude in GHCi, they work fine. When I try to compile the .hs file with these two lines, I get the following:
ch4_test.hs:2:1: error:
Parse error: module header, import declaration
or top-level declaration expected.
|
2 | fst (1,2)
| ^^^^^^^^^
Failed, no modules loaded.
I've googled this error and can't find any explanation what I'm doing wrong.
From a newbie to future newbies: The interactive environment ghci would lead you to believe that you can punch some expressions into an .hs file and run the thing (in a similar fashion to languages like swift and ruby). This is not the case.
Haskell needs an entrypoint called main. Quoting:
Here is a simple program to read and then print a character:
main :: IO ()
main = do c <- getChar
putChar c
The use of the name main is important: main is defined to be the entry point of a Haskell program (similar to the main function in C), and must have an IO type, usually IO ()
Source: https://www.haskell.org/tutorial/io.html
You can't just put any expression in a hs file.
As the error message says, you need a declaration here. For example:
main =
print (fst (1,2)) >>
print (snd (1,2))
I am getting this error but the cause appears to be completely different from anything posted here. And the error message is not at all helpful.
Using Cabal version 3.6.2.0 with GHCI 8.10.7 on MacOS High Sierra (10.13)
I'm working from this page: https://www.tutorialspoint.com/haskell/haskell_modules.htm
specifically the "custom modules" section. There you can see the code I copied and pasted.
Besides the tutorial not mentioning I needed to add "other-modules: Custom" to myfirstapp.cabal, and besides the fact that the sample Custom.hs file includes "if x 'rem' 2 == 0" rather than "if x rem 2 == 0", here is the problem:
Indentation matters!
This line (inside the quotes) does NOT work "if x rem 2 == 0".
This line DOES work " if x rem 2 == 0"!
Indenting by one space is the difference between success and failure.
I'm totally new to Haskell. I've programmed extensively in PHP, Javascript, and Applescript, and dabbled in a dozen others, and this is the first time I've seen white space matter. I assume this is commonly known amongst Haskell veterans, but it would certainly be nice if that was included prominently in the documentation.

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

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.
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.
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
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.

How does Haskell hide data constructor?

I explored System.Random.StdGen and saw this code in the source.
data StdGen = StdGen Int32 Int32
It seems the module export StdGen too.
module System.Random (
RandomGen(next, split, genRange)
, StdGen
...
However, why can't I do this in my code, say like,
Prelude System.Random> StdGen 1 2
Not in scope: data constructor `System.Random.StdGen'**
In the other hand, I can do this,
module F (Foo) where
import GHC.Int
data Foo = Foo GHC.Int.Int32 GHC.Int.Int32 deriving (Show)
and
Prelude> Foo 1 2
Foo 1 2
Would someone please kindly tell me how actually this data constructor is hidden?
There are two things to understand here. Export syntax and a difference in GHCi behaviour between compiled and interpreted values.
Export syntax
Exporting from a module using this syntax
module System.Random (
-- ...
, StdGen
-- ...
tells GHC only to export the datatype, not the constructor (even if both have the same name). The constructor can be listed explicitly within parentheses after the datatype name if you want to export it, like this:
StdGen(StdGen)
Or you can export a datatype with all its constructors like this:
StdGen(..)
GHCi behaviour
In addition, GHCi, when loading an interpreted module, always allows you to see all the entities visisble at the top-level of the module, even if they're hidden by the export list. This is to facilitate development and debugging, and is the reason why your Foo is visible.
This mode where "everything" is visible is reflected by putting a * in front of the module name at the GHCi prompt. If there's a *, everything is visisble, and if not, then the exported entities are visible.
When using the :m command to add or remove modules from scope, you can select whether you want to add modules in *-form or not.
But for compiled modules (and a library module like System.Random usually is compiled), the *-form is not available, so for these you'll always be in the situation that the export list is respected.
See the documentation for a full description of the scoping behaviour of GHCi.
If you look at the sources, you'll see something along the lines of:
module System.Random
(
-- stuff...
, StdGen
-- even more stuff...
)
This syntax means that only the type is exported, not its constructor(s). If you want to export the constructor too, you'd do:
module System.Random
( StdGen(..)
-- ...
)

Haskell functions in GHCi

I am completely new to Haskell. I have been trying to learn how to write functions, lets say to add two integer numbers. I am currently using GHCi to code Haskell. I tried learning from http://www.haskell.org/tutorial/functions.html, however this does not work, I get a not in scope error. I greatly appreciate any help with this. Am I supposed to not use GHCi to code haskell in order to create functions? GHCi, seems to work okay so far, for everything other than functions.
Many thanks in advance.
You have to use let to declare functions in GHCI
ghci>let add x y = x + y
ghci>add 3 3
6
In general though I would advice you to open up a text editor and write your functions in there, save as .hs and open it with :l in ghci
Like this ( from RWH)
-- file: ch03/add.hs
add a b = a + b
Then:
ghci> :l add.hs
[1 of 1] Compiling Main ( add.hs, interpreted )
Ok, modules loaded: Main.
ghci> add 1 2
3

Functions in Haskell

I'm new to functional programming. I have a basic question.
I'm using the Hugs interpreter,
I would like to write a function in Haskell; I went though several tutorials, but I'm not getting it.
fact :: Int -> Int
fact n = if n == 0 then
1
else
n * fact (n-1)
This gives me a syntax error :-S
ERROR - Syntax error in input (unexpected `=')
I assume you type this right into the interactive prompt. Sadly, these are relatively primitive in Haskell - complex definitions, such as fact, can't be entered at the prompt, at least not in the same way you'd normally write them.
You need to put function definitions etc. into modules, then load those via (e.g.) :load fact.hs. There are resources for Hugs specifically that provide more information on this and other topic (I used http://cvs.haskell.org/Hugs/pages/hugsman/index.html to check my assumptions).
Also note that indentation matters, so the code won't work the way you posted it here even when in a module. Those tutorials will have correct versions. If not, they're useless and you should forget them.
The syntax is incorrect. In Haskell, whitespace matters, much like it does in Python. More specifically, if you have text that starts on the first column of a line, the interpreter will think it's a top-level declaration. The correct syntax would be (for example):
fact :: Int -> Int
fact n = if n == 0
then 1
else n * fact (n-1)
You could also put the if in one line if you'd like to. So if you're using an interactive prompt you could do:
λ> let fact n = if n == 0 then 1 else n * fact (n-1)
Notice that you'll need to use let in order to define functions on the prompt (at least this is how it's done in GHCi, I'm not sure about Hugs). You'll be better off putting them in a separate file and then loading that in the interpreter. But anyway, a much nicer solution would use pattern-matching in my opinion anyway:
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n-1)
Here, the interpreter would pattern-match the first argument of the function against the possible cases listed. So if the first argument is null, the result if 1, otherwise apply the function recursively.
Create a file named, for example, fact.hs
-- copying cedric's nicely formatted code
fact :: Int -> Int
fact n = if n == 0
then 1
else n * fact (n-1)
That's all that really needs to be there. When you want to make real modules, you should do some extra stuff.
Now, open up ghci from the same folder. At the ghci prompt, use the :l command to load the "module"
Prelude> :l fact.hs
[1 of 1] Compiling Main ( fact.hs, interpreted )
Ok, modules loaded: Main.
*Main> fact 3
6
*Main> fact 10
3628800
I assume it's a very similar process with Hugs. I think hugs requires the file name to be capitalized. ghci simply creates a "Main" module and puts your code in it; that's why the prompt changes from Prelude> to *Main>
When I work on small Haskell functions, I usually keep two terminals open: one for vim and one for ghci. When I change the file in vim (and save it), I just use :r in ghci to reload the new definitions.
*Main> :r
Ok, modules loaded: Main.
It should be mentioned that the most elegant way to write this function is:
fac n = product [1..n]
See http://www.willamette.edu/~fruehr/haskell/evolution.html for details.

Resources