Reading Simple Haskell
soupi.github.io
soupi.github.io
Also, readers might be interested in A Tour of Go in Haskell, which is the concurrency chapter of A Tour of Go, but just...in Haskell - https://a-tour-of-go-in-haskell.syocy.net/en_US/index.html.
I realized pretty early on all these were just functions, that was cool experience for me. Even the types are sort of functions.
add :: (->) Int Int add x y = x + y
[0] https://www.reddit.com/r/haskell/comments/7ilhb9/a_tour_of_g...
[1] https://hackage.haskell.org/package/gochan-0.0.2/docs/Contro...
Please be considerate towards the visually impaired, and don't break zoom on one of the few browsers that actually even have a somewhat useful zoom function!
[0]: https://github.com/soupi/rfc/blob/master/reading_haskell.md
For the most part the code in the research papers actually _is_ valid Haskell, provided you enable the -XUnicodeSyntax extension and include a few extra modules. Haskell 98 permits Unicode symbols and identifiers; the extension covers the handful of symbols which are built in to the language or enabled by other extensions. You can find a full list here: https://downloads.haskell.org/~ghc/latest/docs/html/users_gu...
Personally I prefer Unicode symbols and tend to use them whenever possible. I have some XCompose rules configured to make them easier to type. Unfortunately, I have yet to find a comparable input system for Windows.
I'd be interested if anyone knows of a simple guide to Haskell's indentation rules - I still find it trips me up now and then.
The "simple" way I deal with it is to use Emacs and press TAB until things look right :)
That's not really true, at least not in the way Python is. Haskell is actually defined using "braceful" syntax, and that syntax can be used anywhere (and is useful for code generation); on top of that it has Layout Rules[0].
Basically:
Any time a "where", "let", "do" or "of" keyword is not followed by a brace, an implicit one is inserted and the indentation of the next lexeme (non-comment non-whitespace item) is noted[1]
For any subsequent line,
* if it's indented by the same amount as the one noted, a semi-colon is prepended
* if it's indented by less than the noted amount, a closing brace is prepended
A closing brace is also inserted when encountering an illegal lexeme (for the current structure) where a a closing brace would be legal.
[0] https://www.haskell.org/onlinereport/haskell2010/haskellch2....
[1] except if the indentation of the next non-whitespace lexeme is less than the current indentation level, then an empty block is inserted, and layout processing for the current scope continues
module Main where {
main = do {
let {
a :: Int; a = 8;
b :: Int; b = 3;
};
let { c = a `quot` b } in print c;
}}
You can also format it all on one line, it'll work just fine: module Main where { main = do {let {a :: Int; a = 8; b :: Int; b = 3;}; let { c = a `quot` b }; print c}}
[0] basically every keyword which opens a non-expression "body", a brace after `case` or `in` is a compilation error as they can only contain a single expressionYou can certainly use indentation and newlines, my examples were just demonstrating the ability to "obviously" not invoke layout since there's nowhere layout information can be.
Whether to use layout (braceless) or explicit structuring (braceful) is solely determined by a brace being present after a listed keyword, you can have any whitespace you want around it, and you can make that decision on a keyword-by-keyword basis[0] although it will apply to the entire block, so you can write
module Main where -- no brace, layout rules
main = do { -- brace, no layout
let { a = 3 };
let { b = 5 };
print $ a + b;
}
Now here the let statement (rather than expression) is a bit tricky because if we don't use the braces the ; will bind to the "let" which is not using layout, resulting in a parse error. An alternative — and the way do blocks normally desugar — is to use ; as a separator prefix, a style also used by e.g. Elm: module Main where
main = do
{ let a = 3
; let b = 5
; print $ a + b
}
[0] this is very very useful when generating code which must surround user-provided code: the generated code can be braceful and the user-provided code can independently use layout without conflicts. if x < 5
then 42
else x
+ 1
+ 2
is legal.Which is partly why OCaml gets some bias from me over Haskell.
so you're saying braceless ifs and fors are bad? yes I agree.
> close the wrong brace
-/+ 1 flipping the right number of braces to get that kind of bug is much much harder than indenting a block incorrectly
Maybe, but enclosing an additional statement or more in your brace because you visually indented it incorrectly is just as easy as in Python.
for (i=0; i<100; i++) {
do_this_100_times();
but_this_just_once(); #oops
}
And if you didn't indent it incorrectly, then it's still possible: for (i=0; i<100; i++) {
do_this_100_times();
but_this_just_once(); # oops
}
whereas in Python it's not: for i in range(100):
do_this_100_times()
but_this_just_once() # correct indentation takes care of itEDIT:
1) as masklinn mentions, the indentation in Python and Haskell works differently. Furthermore, Python can have expressions as top-level, which Haskell cannot, and you can also have if statements with no else in Python, which again, in Haskell you cannot.
2) I know of no formatters for Haskell which will change the semantics, since they all rely on rendering an AST of the code (IIRC).
3) Ocaml is also white-space sensitive, so I don't see the point in the comparison there?
4) You would need to have some pretty contrived code for it to both satisfy the parser and type-check and be wrong logic caused by moving an indentation.
Like, you can't do it in a function that's a if-then-else plainly, nor a case-statement. Maybe a where statement, but then you just promoted the function to top-level, which will not be a problem unless it's shadowing something else, for which you'll get a compiler warning.
Show me some code, and then I'll consider the point valid, I just can't come up with any examples.
main = do
let print = putStr . (++ " ") in do
print "happy"
print "holidays" -- indentation sensitive
putStrLn "!"
De-indenting the marked line by 2 spaces exposes some scroogey irony.(Note that compiler warnings give a hint about the bad idea in this code, but nested do's can have this problem without warnings also.)
The example you gave requires to change logic - because indentation is a part of the logic here.
Ocaml uses whitespace (including newlines) for exactly one reason: token separation. Indentation and line breaks are arbitrary, and can be replaced with spaces in any sequence of Ocaml statements. The same cannot be said for Haskell.
With semicolons and curly braces; Haskell's newline/indent syntax is merely an aesthetic substitute for those.
For that to be valid criticism, it must be particularly hard to write a beautifier for languages with significant whitespace relative to other languages.
I don’t think it is. Beautifying C, for example, also can be tricky in the presence of nested comments (potentially of different types) and nested if statements, some without else clauses, some without {}.
C comments do not nest.
If that's buggy, then there's a larger problem in my opinion.
Actually, in Haskell too, but as the GP said, it is almost impossible that it becomes a problem on practice.
Sounds like you made a mistake, then, because indentation is optional in Haskell: https://en.m.wikibooks.org/wiki/Haskell/Indentation#Explicit...
It described a family of languages called ISWIM, with a staggering number of durable inventions. It's widely recognized as the precursor to ML and Haskell. One of the inventions is the "off-side rule" for indentation sensitive parsing.
The last section of the paper, after the author's conclusion, is a transcript of the discussion at the conference. The first question is from Naur:
Regarding indentation, in many ways I am in sympathy with this, but I believe that if it came about that this notation were used for very wide communication and also publication,you would regret it because of the kind of rearrangement of manuscripts done in printing, for example. You very frequently run into the problem that you have a wide written line and then suddenly you go to the Communications of the ACM and radically, perhaps, you have to compress it. The printer will do this in any way he likes; he is used to having great freedom here and he will foul up your notation.
Next, Floyd:
Another objection that think is quite serious to indentation is that while it works on the micro-scale—that is, one page is all right—when dealing with an extensive program, turning from one page to the next there is no obvious way of indicating how far indentation stretches because there is no printing at all to indicate how far you have indented. I would like you to keep that in mind.
It's a very old discussion.
This argument may sound like admission of imperfectness of printing process.
I can't link to the slide because of the way these pages are defined:
slide 11: The presented argument order in the ASCII-art of Red, Blue, Green I think should be Red, Green, Blue to match the usual initialism.
I could not find a way to submit a pull-request for this presentation, and my search-fu on github failed to find the associated repo, and there were no links I could find in the presentation to submit comments.
You can find the document and repo here:
x +- y = (x + x) - (y + y)
That's crazy.I should learn Haskell (again).
(+-) x y = (x + x) - (y + y)
Symbol operators are automatically infix though, and you can make them normal using (), same as backticks make normal functions infix, `a la 2 `plus` 3.tree ="