The traditional theories about parsing and their implementations in tools like yacc, lex, antlr, etc. are not that important in practice. I also used them in some university courses, but after I encountered parsing problems in practice it seemed easier to just implement a recursive descent parser in the host language.
First, you have to learn the DSL's of these tools (which are non-trivial in detail). Second you have to integrate them into your toolchain. Third - and that is my biggest complaint - you have to connect the Parser combinator's AST to your domain AST. The last thing is pretty amusing as I consider it the main purpose of a parser.
In practice (hopefully after evaluating the need for a custom data format as it might be possible to hijack existing languages and standards) I either use a combinator-parser (if FP available) or an ad-hoc recursive descent parser. Maybe I consider a lexer but the representation of tokens is also a non-trivial decision.
You can access that content by installing something like Hola plugin in your browser, works quite well for watching 'Hey I've Got Bit More News For You' ;)
Yes, there are always too many ideas to explore and too less time. However if you want to look into a static typed functional language I would go with Haskell as it tries harder to exploit a type system to do useful work (although there are even more sophisticated ways to do programming, i.e. by writing proofs (~= programs) in proof-systems, e.g. coq, Isabelle, etc.).
I was introduced to OCaml at my University, but switched later to Haskell and it seemed simpler too me. Furthermore Haskell's ecosystem seems to be more major (or maybe just more vocal?).
I am a fan of Scheme but never got that statement. Why do people say Scheme/Lisp has no syntax? I mean clearly it has a _simple_ syntax, i.e. an expression is either an atom (an identifier, a number, a lambda expression, etc.) or a list of expressions, denoated by "(expr0 expr1 ... exprN). I would say it has a simple, well-thought and powerful syntax.
It has no syntax (of its own) in that it hijacks s-expression syntax instead. When you want to write Lisp code, you actually write some data structures in the s-expression data format, like when writing some data in JSON or XML. Then a Lisp interpreter or compiler uses an s-expression parser to read that data structure into memory, and operates on that.
Then again, not just every Lisp dialect but even pretty much every implementation has its own s-expression parser with its own extensions to s-expression syntax to make it most convenient to write code in, so there's not a very good decoupling after all. :-P Nevertheless it provides some benefits. Like being able to use something like "paredit" to edit code structurally, and making macro systems somewhat simpler (though hygienic macro systems cannot work with pure s-expression data; it must be annotated with lexical context).
You might find it hard to believe but I love Lisp syntax with all of its parentheses, and am explicitly against, for example, Sweet Expressions (SRFI-110). (Though SRFI-105 is fine.)
By the way another meaning of the word "syntax" actually refers to something within the data structures after the actual concrete syntax has been parsed away. For example when you have a list and its first element is the symbol "if", then that list is a usage of the if syntax. This syntax takes three arguments (further elements of the list): a test, consequent, and alternative. So "syntax" is something like a function here, except it operates during compilation and its arguments are unevaluated sub-structures (roughly, code snippets, though the syntax could interpret them however it wants, like for example how the "lambda" syntax's first argument is a parameter list). That's why we can say "in other languages you can only implement new functions; in Lisp you can also implement new syntax." (In the form of macros.)
> It has no syntax (of its own) in that it hijacks s-expression syntax instead. When you want to write Lisp code, you actually write some data structures in the s-expression data format, like when writing some data in JSON or XML. Then a Lisp interpreter or compiler uses an s-expression parser to read that data structure into memory, and operates on that.
My point is that the s-expression format has to be defined (obviously), e.g. you enclose lists in '(' and ')' characters, space symbols separate tokens, etc. In my world these rules are consequences of a defined syntax and saying there is no syntax is just wrong. The reader parses at some point a byte sequence and builds an AST. That Lisp/Scheme has such a simple syntax is a powerful feature of the language but saying it has no syntax just contributes to the belief of misinformed people that Lisp is some kind of strange Voodoo-language which is a bad thing as it is a powerful tool.
It is true that it is a little more nuanced than "has no syntax". The core of the language has very little syntax relative to many of the more popular languages but it still does have some syntax. The confusion also arises because often the syntax it does have looks just the same as function invocation. "or" is syntax whereas "+" is not but they both look the same in invocation. (or fu bar) and (+ 1 2) but "or" is short circuiting and "+" is not. "or" is syntax but it doesn't look like the syntax a lot of people are used to.
In fact, if you use scheme extensively you will probably use more syntax than most languages. Scheme and other lisps are very good at allowing you to create new syntax which is very helpful in creating DSLs which you will run across a lot in scheme libraries and the SRFIs.
I am not so sure with that. Say, your program is used in a shell script and is invoked badly - you might want to print its usage then. If you exit normally your shell script might break weirdly but if you exit with error it's easier to spot the reason of failure.
On the other hand you made me thinking and probably you should have three code passes per default:
[0] normal behaviour (exit 0)
[1] bad arguments (exit EINVAL)
[2] --usage (print to stdout but but exit != 0)?
Anyway I am not sure if it makes sense to declare "usage" as normal behaviour.
In my book, there is a difference between explicitly asking for help/usage and passing arguments that do not make sense, which triggers the output of help/usage.
The former, I think, should write to stdout and return 0, the latter should write to stderr and return something non-zero.
Giving help if the user asks for it is normal behaviour.
First, you have to learn the DSL's of these tools (which are non-trivial in detail). Second you have to integrate them into your toolchain. Third - and that is my biggest complaint - you have to connect the Parser combinator's AST to your domain AST. The last thing is pretty amusing as I consider it the main purpose of a parser.
In practice (hopefully after evaluating the need for a custom data format as it might be possible to hijack existing languages and standards) I either use a combinator-parser (if FP available) or an ad-hoc recursive descent parser. Maybe I consider a lexer but the representation of tokens is also a non-trivial decision.