Why shouldn't I mix tabs and spaces? - haskell

I often read that I shouldn't mix tabs and spaces in Haskell, or that I shouldn't use tabs at all. Why?

The problem is twofold. First of all, Haskell is indentation sensitive, e.g. the following code isn't valid:
example = (a, b)
where
a = "Hello"
b = "World"
Both bindings need to be indented with the same number of spaces/tabs (see off-side rule). While it's obvious in this case, it's rather hidden in the following one, where I denote a space by · and a tab by »:
example = (a, b)
··where
····a = "Hello"
» b = "World"
This will look like valid Haskell code if the editor will show tabs aligned to multiples by four. But it isn't. Haskell tabs are aligned by multiples of eight, so the code will be interpreted like this:
example = (a, b)
··where
····a = "Hello"
» b = "World"
Second, if you use only tabs, you can end up with a layout that doesn't look right. For example, the following code looks correct if a tab gets displayed with six or more spaces (eight in this case):
example = (a, b)
» where» a = "Hello"
» » b = "World"
But in another editor that uses 4 spaces it won't look right anymore:
example = (a, b)
» where» a = "Hello"
» » b = "World"
It's still correct, though. However, someone who's used to spaces might reindent b' binding with spaces and end up with a parser error.
If you enforce a code convention throughout your code that makes sure that you only use tabs at the beginning of a line and use a newline after where, let or do you can avoid some of the problems (see 11). However, current releases of GHC warn about tabs by default, because they have been a source of many parser errors in the past, so you probably want to get rid of them too.
See also
A reddit thread on the topic (majority pro spaces, but some pro tabs)
Good Haskell Style (pro spaces)
Yet Another Tabs v Space debate (pro mixing)

Related

Different outputs in GHCI

Running this with M 1 will show a new line and a will show the characters "\n" in the ghci output.
Since they are the same characters i would expect the same behaviour.
Any reason why?
data V = M Int
instance Show V where
show m = a
a :: [Char]
a = "\n"
Whenever a value is displayed in GHCi, it uses the Show instance of that object to convert it to human-readable text by applying the show function, then printing the resulting String. In your case, what is happening is:
You have defined the Show instance of V to be a constant "\n", or newline. Thus when GHCi tries to display a value of type V it outputs a newline.
By contrast, the Show instance of String is defined in such a way that for any string s, show s will output the Haskell representation of s. For instance, show "\n" will give a result of "\"\\n\" (i.e. quotation mark, backslash, n, quotation mark). (Try running show "myString" in GHCi and seeing the result for different strings to get an idea of how this works.) Thus when GHCi displays a String, it takes the string (a newline, in your case), converts it to a human-readable format with escape characters using show, and then displays that new string.
Why is show implemented in this convoluted way for strings? I’m not quite sure, but one possibility is disambiguation: show 1 is "1", but show "1" is "\"1\"". When printed to the console, the former is clearly a number, whereas the latter is clearly a string.

Whitespace - Not printing second character

s = space; l = line break; t = tab
ssstsssttsl
tl
ssl
sssttsssstl
tl
ssl
This only prints F and not a. I am not very certain about stacks and it is probably something to do with that.
I put your code into this online IDE: https://whitespace.kauaveel.ee/
It includes an on-the-fly disassembler, which is nice.
As is, your code produces an "Unexpected EOF" error. This is because of the last linebreak (l). Removing that gives
push 70
printc
label_0:
printc
from the disassembler. I.e. what you thought was your second push is actually a label instruction.
This is because the printc instruction is actually just tlss. You have an extra l after that, which combined with the following two spaces forms lss (label).
Fixed code:
s s s t s s s t t s l
t l
s s s s s t t s s s s t l
t l
s s

Standard ML string to a list

Is there a way in ML to take in a string and output a list of those string where a separation is a space, newline or eof, but also keeping strings inside strings intact?
EX) hello world "my id" is 5555
-> [hello, world, my id, is, 5555]
I am working on a tokenizing these then into:
->[word, word, string, word, int]
Sure you can! Here's the idea:
If we take a string like "Hello World, \"my id\" is 5555", we can split it at the quote marks, ignoring the spaces for now. This gives us ["Hello World, ", "my id", " is 5555"]. The important thing to notice here is that the list contains three elements - an odd number. As long as the string only contains pairs of quotes (as it will if it's properly formatted), we'll always get an odd number of elements when we split at the quote marks.
A second important thing is that all the even-numbered elements of the list will be strings that were unquoted (if we start counting from 0), and the odd-numbered ones were quoted. That means that all we need to do is tokenize the ones that were unquoted, and then we're done!
I put some code together - you can continue from there:
fun foo s =
let
val quoteSep = String.tokens (fn c => c = #"\"") s
val spaceSep = String.tokens (fn c => c = #" ") (* change this to include newlines and stuff *)
fun sepEven [] = []
| sepEven [x] = (* there were no quotes in the string *)
| sepEven (x::y::xs) = (* x was unquoted, y was quoted *)
in
if length quoteSep mod 2 = 0
then (* there was an uneven number of quote marks - something is wrong! *)
else (* call sepEven *)
end
String.tokens brings you halfway there. But if you really want to handle quotes like you are sketching then there is no way around writing an actual lexer. MLlex, which comes with SML/NJ and MLton (but is usable with any SML) could help. Or you just write it by hand, which should be easy enough in this case as well.

Haskell syntax error for where statement [duplicate]

This question already has an answer here:
Why shouldn't I mix tabs and spaces?
(1 answer)
Closed 6 years ago.
I'm writing some Haskell code to learn the language, and I've run into the syntax error:
Vec2.hs:33:27: parse error on input '='
The code I've written here is below. The error is pointing at the 2nd term in vec2Normalize iLength = ... I don't see the syntax error
-- Get the inverse length of v and multiply the components by it
-- Resulting in the normalized form of v
vec2Normalize :: Vec2 -> Vec2
vec2Normalize v#(x,y) = (x * iLength, y * iLength)
where length = vec2Length v
iLength = if length == 0 then 1 else (1 / length)
Some guessing involved since you don’t provide the complete code, but this error could indicate that your line iLength = ... is not properly indented; actually, that the iLength starts to the right of the length = on the line before.
Does your original file use tabs instead of spaces for indentation? If so, be aware that Haskell always interprets a tab as spanning 8 columns. So, e.g.,
<TAB>where length = ...
<TAB><TAB><SPACE><SPACE>iLength = ...
would be interpreted as
where length = ...
iLength = ...
thus causing the error, even though your editor might show the lines properly aligned if it uses 4-column tabs.
You are using tabs for indentation, so the second definition in the where clause is actually not aligned with the first one. Haskell uses a tab width of 8 spaces, which may be different from your editor, leading to problems like this where the code looks okay, but really isn't.
I strongly recommend that you configure your editor to use spaces only when working with Haskell code.

Multiline string literal in Matlab?

Is there a multiline string literal syntax in Matlab or is it necessary to concatenate multiple lines?
I found the verbatim package, but it only works in an m-file or function and not interactively within editor cells.
EDIT: I am particularly after readbility and ease of modifying the literal in the code (imagine it contains indented blocks of different levels) - it is easy to make multiline strings, but I am looking for the most convenient sytax for doing that.
So far I have
t = {...
'abc'...
'def'};
t = cellfun(#(x) [x sprintf('\n')],t,'Unif',false);
t = horzcat(t{:});
which gives size(t) = 1 8, but is obviously a bit of a mess.
EDIT 2: Basically verbatim does what I want except it doesn't work in Editor cells, but maybe my best bet is to update it so it does. I think it should be possible to get current open file and cursor position from the java interface to the Editor. The problem would be if there were multiple verbatim calls in the same cell how would you distinguish between them.
I'd go for:
multiline = sprintf([ ...
'Line 1\n'...
'Line 2\n'...
]);
Matlab is an oddball in that escape processing in strings is a function of the printf family of functions instead of the string literal syntax. And no multiline literals. Oh well.
I've ended up doing two things. First, make CR() and LF() functions that just return processed \r and \n respectively, so you can use them as pseudo-literals in your code. I prefer doing this way rather than sending entire strings through sprintf(), because there might be other backslashes in there you didn't want processed as escape sequences (e.g. if some of your strings came from function arguments or input read from elsewhere).
function out = CR()
out = char(13); % # sprintf('\r')
function out = LF()
out = char(10); % # sprintf('\n');
Second, make a join(glue, strs) function that works like Perl's join or the cellfun/horzcat code in your example, but without the final trailing separator.
function out = join(glue, strs)
strs = strs(:)';
strs(2,:) = {glue};
strs = strs(:)';
strs(end) = [];
out = cat(2, strs{:});
And then use it with cell literals like you do.
str = join(LF, {
'abc'
'defghi'
'jklm'
});
You don't need the "..." ellipses in cell literals like this; omitting them does a vertical vector construction, and it's fine if the rows have different lengths of char strings because they're each getting stuck inside a cell. That alone should save you some typing.
Bit of an old thread but I got this
multiline = join([
"Line 1"
"Line 2"
], newline)
I think if makes things pretty easy but obviously it depends on what one is looking for :)

Resources