"-- file:" in Haskell - haskell

I've been reading my textbook and here's something bothering me:
One of the page shows some code like this:
-- file: ch02/add.hs
add a b = a + b
Then load it in ghci. However, when I type the first line it ghci, it does nothing, then the second line triggered an error.
I guess these two lines mean that I should create a file and put them in, then load it. But the ghci told me it couldn't recognize "--", though the second line performed well as a function. So I'm confused: shouldn't "--" mean something like "//"? Did I misunderstand the textbook?
Thank you.

First, loading a file is not the same as typing lines in ghci. ghci works like in a do block of some IO action (hence you'd need to write let add a b = a + b), whereas a Haskell file simply contains top-level declarations.
FWIW, you can simply leave out the first line. As you've noticed, that's just a comment. The problem in your file is that you have not written
-- file: ch02/add.hs
but
— file: ch02/add.hs
(you're probably using a text editor which merges two hyphens to an em-dash). And the em-dash isn't recognised as a special symbol in Haskell. Actually, it can be used like any other infix:
(—) :: Int -> Int -> Int
a — b = a - b
Use a proper plaintext editor or IDE and you shouldn't have such problems, for advice see here.

Related

Preprocessor for haskell source: is cpp the only option?

I can see from plenty of Q&As that cpp is the usual preprocessor for Haskell source; but that it isn't a good fit for the job. What other options are there?
Specifically:
Haskell syntax is newline-sensitive and space/indent-sensitive -- unlike C, so cpp just tramples on whitespace;
' in Haskell might surround a character literal, but also might be part of an identifier (in which case it won't be paired) -- but cpp complains if not a char literal;
\ gets a trailing space inserted -- which is not a terrible inconvenience, but I'd prefer not.
I'm trying to produce a macro to generate an instance from parameters for a newtype type and corresponding data constructor. It needs to generate both the instance head and constraints and a method binding. By just slotting the constructors into an instance skeleton.
(Probably Template Haskell could do this; but it seems rather a large hammer.)
cpphs seems to be just about enough for my (limited) purposes. I'm adding this answer for the record; an answer suggesting cpphs (and some sensible advice to prefer Template Haskell) was here and then gone.
But there's some gotchas that meant at first sight I'd overlooked how it helped.
Without setting any options, it behaves too much like cpp to be helpful. At least:
It doesn't complain about unpaired '. Indeed you can #define dit ' and that will expand happily.
More generally, it doesn't complain about any nonsense input: it grimly carries on and produces some sort of output file without warning you about ill-formed macro calls.
It doesn't insert space after \.
By default, it smashes together multiline macro expansions, so tramples on whitespace just as much.
Its tokenisation seems to get easily confused between Haskell vs C. specifically, using C-style comments /* ... */ seems to upset not only those lines, but a few lines below. (I had a #define I wanted to comment out; should have used Haskell style comments {- ... -} -- but then that appears in the output.)
The calling convention for macros is C style, not Haskell. myMacro(someArg) -- or myMacro (someArg) seems to work; but not myMacro someArg. So to embed a macro call inside a Haskell expression probably needs surrounding the lot in extra parens. Looks like (LISP).
A bare macro call on a line by itself myInstance(MyType, MyConstr) would not be valid Haskell. The dear beastie seems to get easily confused, and fails to recognise that's a macro call.
I'm nervous about # and ## -- because in cpp they're for stringisation and catenation. I did manage to define (##) = (++) and it seemed to work; magicHash# identifiers seemed ok; but I didn't try those inside macro expansion.
Remedies
(The docos don't make this at all obvious.)
To get multi-line output from a multi-line macro def'n, and preserving spaces/indentation (yay!) needs option --layout. So I have my instance definition validly expanded and indented.
If your tokenisation is getting confused, maybe --text will help: this will "treat input as plain text, not Haskell code" -- although it does still tolerate ' and \ better. (I didn't encounter any downsides from using --text -- the Haskell code seemed to get through unscathed, and the macros expanded.)
If you have a C-style comment that you don't want to appear in output, use --strip.
There's an option --hashes, which I imagine might interact badly with magicHash#.
The output file starts with a header line #line .... The compiler won't like that; suppress with --noline.
I would say that Template Haskell is the most perfect tool for this purpose. It is the standard set of combinators for constructing correct Haskell source code. After that there is GHC.Generics, which might allow you to write a single instance that would cover any type which is an instance of Generic.

Can anything done in a Haskell script be reproduced in a GHCi session?

I want to run the function
act :: IO(Char, Char)
act = do x <- getChar
getChar
y <- getChar
return (x,y)
interactively in a GHCi session. I've seen elsewhere that you can define a function in a session by using the semi-colon to replace a line-break. However, when I write
act :: IO(Char, Char); act = do x <- getChar; getChar; y <- getChar; return (x,y)
it doesn't compile, saying
parse error on input ‘;’
I've elsewhere seen that :{ ... }: can be used for multiple line commands, but typing
:{ act :: IO(Char, Char)
and then hitting enter causes an error--perhaps I'm misunderstanding how to use them.
Besides just getting this particular case to work, is there a generic way of taking code that would run in a Haskell script and making it run in an interactive session?
You can't just insert semicolons to replace each line break. Doing stuff on one line means opting out of the layout rule, so you have to insert your own semicolons and braces. This means you need to know where those braces and semicolons would be required without the layout rule. For this case in particular, each do block needs braces around the whole block, and semicolons between each operation. The layout rule normally inserts these for you based on indentation.
So to write this specific example on one line, you can do this:
let act :: IO(Char, Char); act = do {x <- getChar; getChar; y <- getChar; return (x,y)}
On a new enough version of ghci you can omit the let as well.
For simple enough do blocks you might even get away with omitting the braces. In your example there's only one place the { and } could possibly go, and so GHCI inserts them even when you do everything on one line. But for an expression with multiple do blocks or other multiline constructs, you will need to insert them explicitly if you want them on one line.
On the broader question:
Besides just getting this particular case to work, is there a generic way of taking code that would run in a Haskell script and making it run in an interactive session?
The closest thing I know of is using the multiline delimiters, ":{ and :} (each on a single line of its own)". They can handle almost anything you can throw at them. They can't handle imports (GHCi does support the full import syntax, but each import must be on its own in a line) and pragmas (the only alternative is :set, which also need a line all of its own), which means you can't help but separate them from the rest of the code and enter them beforehand.
(You can always save the code somewhere and load the file with :l, and that will often turn out to be the more convenient option. Still, I have a soft spot for :{ and :} -- if I want no more than trying out half a dozen lines of impromptu code with no context, I tend to open a text editor window, write the little snippet and paste it directly in GHCi.)

How do I configure VIM to use different syntaxes in different parts of a file?

I have a file that works like this:
:: JavaScript
function whatIsThis(){
return "an example";
}
:: Haskell
main = putStrLn "is this is an example?"
:: C
#include <stdio.h>
int main(){
printf("yes, it is");
};
In other words, a line starting with :: determines the syntax of the next lines until another :: is found. Is there any way to configure vim to highlight the syntax of those blocks correctly?
Have a look at my SyntaxRange plugin; it offers both a :[range]SyntaxInclude command, and functions to define regions (based on start and end patterns) to highlight with a particular syntax. For your example:
call SyntaxRange#IncludeEx('start="^:: Haskell" end="^::"me=e-3', 'haskell')
call SyntaxRange#IncludeEx('start="^:: C" end="^::"me=e-3', 'c')
call SyntaxRange#IncludeEx('start="^:: JavaScript" end="^::"me=e-3', 'javascript')
If you want to have full editing capabilities for each separate part (i.e. filetype-specific settings, customizations, mappings, commands), not just specific syntax highlighting, you won't get around having a separate buffer for each fragment (as these things are all tied to the buffer's filetype).
With the NrrwRgn - A Narrow Region Plugin similar to Emacs, you can cut up the original file into separate buffers (shown e.g. in split windows), and the plugin syncs any changes back to the original automatically.

Haskell the function 'main' is not defined?

Here is my basic program, but it states the function 'main' is not defined in module 'Main' how can I fix this?
here is my program
main = do
-- variable
a <- getLine
putStrLn a
Your code is missing indentation, Haskell uses indentation to figure out where a block ends.
main = do
a <- getLine
putStrLn a
Above is the proper indented form of your code; you should probably read the article here which explains it far better than I.
This error message means simply that the compiler didn't find a definition of your function main.
To run your compiled program, rather than interact with it in ghci (which I'd recommend you do as a beginner), you need main::IO ().
If you don't give your module a name, it automagically does the equivalent of inserting module Main where at the top of your file.
I can't think of any way to produce this error other than to
accidentally comment out main with -- or {- other comment syntax -}
spell the word main incorrectly
accidentally compile an empty file.
(
Although your question appears to show incorrect indentation, that's because this site does not treat tabs as 8 characters wide. I suspect you indented the main by four spaces to get it to format as code in your question. In any case the compiler didn't give an error message consistent with an indentation error.
I'd like to recommend you use spaces rather than tabs for indentation, as it's unfailingly irritating to have to debug the whitespace of your program.
Most editors can be configured to turn a tab key press into an appropriate number of spaces, giving you the same line-it-up functionality with none of the character count discrepancies.
)

GHCi usage question

I am studying Haskell and use Emacs+Haskell mode as my editor.
After playing some simple expressions in GHCi, I am wondering whether these IDE/editor functionality that exist in Visual Stuido for F#:
Can I send the content in the clipboard into the interpreter? Currently I can only :load the file into the interpreter. This is inconvienent when I gradually write functions in a script file. Like 'Alt+Enter' in visual stuido.
After compiling, I hope to see the signature of the function, e.g.
let double x = x + x
so that I can better understand the type inference mechanism in Haskell.
On Windows, there's WinGHCi, a gui including (poor, but often sufficient) support for copy and paste. Dunno about the command line version.
Use :type double (or the shortcut :t double) to get the type signature of double. There's also :info which applies to values (including functions) as well as types and typeclasses (e.g. :info Bool lists the definition of Bool and all typeclasses it is an instance of) and says where it was defined.
Regarding question 2, to see the inferred type of an expression every time you type one in, you can give inside ghci :set +t . I think you could also put that in a .ghci file, inside your home directory, as described in http://www.haskell.org/ghc/docs/6.12.2/html/users_guide/ghci-dot-files.html .
As far as I know, there is no support for sending the clipoards to the interpreter "out of the box", but it should not take more than couple of lines of elisp. I'd look in the support modes for other languages and copied it from there if I were you.
Regarding the types, you could type C-c C-t or C-c C-i on any symbol in your code, which would trigger ":t <symbol>" and ":i <symbol>" commands in the ghci process
TAIM claims to send selected expressions in vim to ghci(haven't tried it)
I'm not sure about function signatures inside the editor but in ghci its ":t func"
Actually looking at their youtube video it looks like TAIM may be able to select ":t func" in vim and send it to interpreter.

Resources