4 ms·
The plain Haskell language, without extensions, has a pretty small and trivial syntax. The Haskell report describes it in approx 250 lines[http://www.haskell.or
by sparkie 13y ago
The plain Haskell language, without extensions, has a pretty small and trivial syntax. The Haskell report describes it in approx 250 lines[http://www.haskell.org/onlinereport/syntax-iso.html http://www.haskell.org/onlinereport/syntax-iso.html]. Admittedly, the syntax can be overwhelming when multiple extensions are involved because there is no single resource which explains them all in full as succinctly as the report.
The difficulty one might find comprehending Haskell is probably because of the semantics rather than syntax - particularly if you have a background in languages like C++ and Java - the first thing you'll be attempting to do is find parallels between this new obscure syntax and what you already know - but they don't necessarily fit, because the language is fundamentally different.
A common example of misunderstanding for beginners is function signatures - in Haskell, one simply defines a function name, followed by two colons, followed by a type declaration which states the function's type. It's as simple as
add :: Int -> Int -> Int
If you're attempting to draw the parallel to the equivalent in another language such as C#, you might think this is the same as
int Add(int a, int b) {
...
}
While pretty close, the Haskell equivalent of that is really a coupled argument.
add :: (Int, Int) -> Int
The C# equivalent of the original is closer to this
Func<int, Func<int, int>> add = a => (b => ...);
At this point it should become a bit more obvious why that "cryptic" function signature is the way it is - it's because all functions in Haskell are secretly single argument functions, and additional arrows indicate that the return type is another function. In other words, the arrow, -> associates to the right, which makes it unnecessary to parenthesize the returned functions - but you can optionally write them for clarity:
add :: Int -> (Int -> Int)
As a result, you can partially apply add with a single value, e.g. `add 5`, and a valid function which adds 5 to its argument is returned, e.g. `(add 5) 6 == 11`, and because function application (denoted by a space) associates to the left, you can omit the parens and simply say `add 5 6`.
Given that you have some Erlang background, the syntax for implementing functions should not be foreign to you, because they're quite similar, except perhaps "do-notation", which will won't be very intuitive until you grok monads.
- arms 13y agoThank you, I found this very helpful. I'm being selfish, but I'd love some more examples like this where you compare the basics in Haskell against more mainstream, imperative languages - it makes it easier to digest.
- kazagistar 13y agoUnfortunately, the semantics get even more different from there. Its like learning to speak a new language, the faster you stop trying to translate things in your head, and just understand them directly, the easier it is. For example, this is the default implementation of foldr, in the Traversable typeclass, in terms of a foldMap implementation: foldr :: (a -> b -> b) -> b -> t a -> b foldr f z t = appEndo (foldMap (Endo . f) t) z This does not take long to grok in Haskell, but translating it to any imperative language would make no sense. It requires an understanding of the semantics of Monoids, currying, function application, and Endofunctors. None of these are hard, but none of them exist in more mainstream imperative languages. But heck, this is at least something like what it is doing: #!python3 from functools import partial def foldr(f, z, t): for endo in (partial(f, i) for i in t): z = endo(z) return z Only, um, not quite, because iterables are not exactly foldables, it lacks the generality of actually calling the foldMap function (which can be different in different types), it has no type signatures so it is less strict about its parameter, and this is cheating a bit because python already has nice functional programming tooling compared to many other languages, and so on. But the jist is there, and even some of the performance qualities of lazyness if you get how iterators work in python. I personally suggest you just learn it from scratch. Its not just a different skin over the same ideas, like so many other languages.
- Shish2k 13y agoI think my main beef with haskell isn't the syntax per se, but the culture of single-letter variable names, which this post so wonderfully demonstrates :P (I know this is just a short demo rather than production code, but all the "good examples of haskell" I saw at university were like that too, and much of the online documentation I saw :/ )
- rhizome31 13y agoMy guess is that this comes from the math culture where single letter variables are the norm.
- kazagistar 13y ago