Ask HN: How would you modify this list of best Perlis languages?

6 points by wrp ↗ HN
Blog aritcles about Perlis languages are popular, but they disappoint me. The surveys are limited by the experience of one individual and the responses are mostly just people giving a shout for their language du jour.

"Perlis language" is a subjective term. That is, does a language represent a new way of thinking for you? On the other hand, I think we can agree that a good Perlis language: * implements the most powerful and representative features of a paradigm * does not require learning much more than what is needed to use the paradigm * does not mix non-orthogonal paradigms * is developed enough that you can build working applications with it

I tried to list every distinct paradigm and match it with the best implementation. Some languages came up as the best for multiple paradigms. There were a few paradigms that I was really interested in but couldn't find a suitable implementation. In the end, I was surprised at how short my list is.

What would you change? Would you argue for a different language, or to add/delete a paradigm?

    C -- procedural
    Forth -- build it yourself
    Emacs Lisp -- macros, code as data 
    Erlang -- impure functional, eager evaluation, dynamic typing, actor concurrency
    Clean -- pure functional, lazy evaluation, static typing
    GNU Smalltalk -- class-based OOP
    Io -- prototype-based OOP, reflection
    APL -- array-based, built on a small set of powerful operators
    Prolog -- unification, backtracking, logic variables

24 comments

[ 7.2 ms ] story [ 86.6 ms ] thread
C feels like it stands alone. What other language would you use to learn about the machinery of computing, and put yourself in the position of having to make everything explicit?

I thought a bit about Google's Go. It gets rid of the preprocessor and cleans up handling of pointers. But it also does away with manual memory management. That may be getting too far away from the machine for learning purposes.

I also thought about Ada, but that seems to impose a heavy learning overhead.

What about going the other direction, down to assembly? Unlike many people, I have no loathing of assembly programming. I find well-structured and commented assembly code to be just as easy to read as similar quality C code. Although it has a reputation for being hard, experienced ASM coders tell me it's just a matter a familiarity. They claim to be just as productive in ASM as in C.

My decision to pass over assembly is because modern processors no longer have a straightforwardly sequential execution model. The image you get from tracing assembly code is only an approximation of what will happen in the processor, which is the same as you can say for C code. So my perception is that there is no particular benefit to knowing ASM any more. (Unless you are working with older, simpler designs as in embedded systems.)

Re: C -- I agree. It's the only widespread language that really matters for this.

Re: Assembly -- I disagree. With the increasing popularity of heterogenous multi-processor systems (cpu + specialized processors like GPUs, etc.) learning languages that are more constrained to the hardware is still valuable/important.

Also, note that building specialized code generators (be they stand along or embedded DSLs) to the assembly language can give you a nice payoff.

I would really like assembly to be a viable addition to the programmer's toolkit. So far, I haven't seen any tutorial material that explains the issues and best practices in modern x86-64 assembly programming. All the books I've looked at for Intel assembly assume the old x86 environment.
Forth brings to mind stack-based languages, but I didn't bill it as representative of that paradigm. For one thing, I'm not sure "stack-based" is a whole paradigm unto itself, rather than just a syntactic convention. Joy and Factor are two languages normally associated with Forth because of the similar syntax, but their development models are very different.

Forth isn't just a framework for expressing algorithms, it's a whole philosophy of system development. You start with nearly nothing, sometimes not even an operating system, and build up precisely and only what you need. http://www.yosefk.com/blog/my-history-with-forth-stack-machi...

Yeah, it's a different philosophy taken to an extreme. :-)

That said, from a practical standpoint, Factor is excellent.

In fact, I'm surprised that more of the recent language implementations haven't used Factor as their backend rather than e.g. llvm.

Prolog gives you nondeterminism. That is, it can take incomplete or inconsistent input and provide partial or multiple answers. That's not behavior you want very often, but when it is, who else you gonna call? The specific, unique features of Prolog are unification, backtracking, and logic variables.

People had high hopes for Prolog in the 1970s, but it proved to be a total disappointment. It was terribly slow and had a complicated performance model. These days, the niche for which Prolog is a good choice is very small. For combinatorial problems, Prolog has been superceded by extensions like Choco and Gecode and by easier and faster dedicated systems like Essence, Minion, and G12. Prolog is still sometimes chosen for small projects in constraint programming or text manipulation.

Be sure to read this article on how Prolog really works. http://www.amzi.com/articles/prolog_under_the_hood.htm

That Prolog is slow and has a complicated performance model is the common wisdom, but both are completely wrong. For a better view of speed, you should look at my Ph.D. dissertation of 1990. It explains how to write a Prolog compiler whose run-time code efficiency rivals that of good C compilers. The two main ideas are global dataflow analysis and direct compilation to native code (no WAM bytecode). For a better view of the performance model, you should read Richard O'Keefe's book from 1990, The Craft of Prolog, which explains very well how to write beautiful and efficient Prolog code.
APL is an array language, with an exceptionally concise syntax allowed by restricted function arity, many operators, and strict right-to-left evaluation. It is still heavily used in the financial industry but little known elsewhere. Since APL is basically a powerful calculator, programmers usually don't take a close look. OK, so APL doesn't cover a lot of the usual territory, but what it does have is really cool. Besides, it's a small language and the best learning tools are free. APL won't take you long to understand and it will give you a better appreciation for the possibilities of array-oriented algorithms in R, MATLAB/Octave, or Python+NumPy.

I like Dyalog and they have a free book (http://www.dyalog.com/intro/) but there are others (http://www.rexswain.com/aplinfo.html)

Io was a hot topic around 2005-2006, but interest has faded. My impression is that the excitement was due to Io's extreme reflection capabilities and runtime dynamism. These are interesting design features and Io is probably one of the best languages for exploring them, but I'm listing it here as a case of protoype-based object-oriented design.

Prototype OOP really was a challenge for this list. Although several prorotype-based languages have been developed, I think only Io and JavaScript have made it into production use. (Unless you count the crippled and long-dead NewtonScript.)

So why not JavaScript? Well, ugh, JavaScript is a mess, not just the language, but also the production environments, the documentation, and the user community. In addition to prototypes, JavaScript incorporates the functional paradigm plus a lot of random warts. Developing JavaScript apps for release is a nightmare because of platform differences. Documentation is little help, because even advanced books on JS take the approach that class-based OOP is what you really want, so they focus on how to hammer JS into something that looks like Java. They are many excellent 3rd party libraries, but they either treat JS as a functional language or force it into the class-based mould. So, I'd answer that you can write good prototype-based code in JavaScript, but you really need to be proficient before going in.

Yeah, Io never got to a (nice/good enough) v1.0 that people could do more than just play around with it. Secondarily, its radical dynamism makes it slow in those shootout benchmarks.
Smalltalk is still the gold standard for class-based object-oriented language design. It doesn't get used much, though. There are the problems with image-based development, external interfacing, cross-implementation differences, unwieldy class libraries, and a bunch of other things.

Ruby gets recommended a lot as a modern alternative. It has a very clean syntax and the OOP machinery is closely copied from Smalltalk. By my experience is that while Ruby code at first seems clean and elegant, it turns out to be confusing. The design philosophy is like Perl, have multiple ways to do anything. The larger and more complicated grammar makes it harder to learn. I thought that while regexes and class management were smoothly integrated, many other syntactic features were inconsistent, nonstandard, or ambiguous. In all, there were just too many other things going on to make Ruby a good vehicle for dipping into class-based OOP.

Python, also, might be suggested, since Python 3 has made the OOP features more integrated than once was the case. However, Python is a big language, there is a lot to become aware of, and the OOP machinery is not all that close to Smalltalk any more.

GNU Smalltalk is what I recommend. It is a straightforward implementation of traditional Smalltalk with one big difference. Instead of being image-based and editable only in the Smalltalk browser environment, GST is text-based. You write code in a text editor as with any other language, though there is also a browser environment available. GNU Smalltalk is designed as a scripting language, so it has the usual facilities for system interaction.

Part of the charm of Smalltalk (or, more objectively, the uniqueness in a Perlis-language sense) is its image-based nature. Smalltalk is the image.

A Smalltalk IDE is unlike any other. The integration of language and 'operating system' changes the way you look at most other languages; it's not just an OO thing. You lose all that if you go running to the familiar, comfortable 'standard' of a text editor.

Personally, I'd suggest Pharo Smalltalk as an ideal starting point: it's clean, modern and under vigorous development, with a thriving community.

Also, I strongly disagree with 'unwieldy class libraries' - I've found the libraries a joy to use. Clear, logical, and very easy to explore even without reams of documentation.

I think this is taking the position that even though the semantics of the language is the same, changing the interface to it can make for a change in programming paradigm. I'm skeptical, but it would be interesting to hear this idea developed more.
Clean is not the language that gets recommended to every pilgrim in search of functional purity, but I think it should be. The syntax is about the same as Haskell, but it comes with a polished IDE, a native GUI library, and excellent documentation.

There is some confusion over the handling of state in Clean versus Haskell. It is usually said that Haskell uses monads and Clean uses uniqueness types. This is partly true. A more accurate explanation that monads and uniqueness types are distinct features that can coincidentally both be used to manage state. Haskell doesn't have uniqueness types. Clean has both, and you can use either, but the developers prefer uniqueness types. Having tried both methods, I'd say that uniqueness types are easier to understand but monads give cleaner structure to the code.

I see so many laments from people who tried Haskell and gave up. My guess is that there would be a much lower attrition rate if they started with Clean instead.

Erlang has so many good things going for it, I think it stands head and shoulders above other dynamic, impure functional languages. Heck, it has actor-based concurrency, failure tolerance, bit-level pattern matching, an excellent development and testing environment, industrial quality libraries, and Prolog syntax. (OK, not everybody thinks that last one is a big plus.)
The prolog-ish syntax is to Erlang as parentheses are to Lisp -- a humungous barrier to entry for a lot of developers.

I think Erlang's legacy is the fact that it's exposing those other features that you mention to a wide audience of language aficionados that they are spreading (gaining legitimacy/traction) within other languages / libraries.

I like Erlang's syntax. The punctuation rules make sense to me and I appreciate how it allows greater code density on the page. When I do have trouble scanning code, it's generally due to the heavy use of pattern matching for flow control. So, I really don't have any feeling for how much of a problem this is for people.

That said, I want to recommend languages that introduce people to new ideas with a minimum of distractions. If the syntax is an issue, then I should point to alternatives. For the important concepts in Erlang, I'd appreciate suggestions.

Lisp has that whole homoiconicity thing going, the code-is-data syntax that makes macro writing super convenient. The thing about Common Lisp, though, is that you have to learn an awfully big chunk of it before you can start building interesting things. That's why I recommended Emacs Lisp. Sure, it's small and has dynamic rather than lexical scoping, but it still has macros. Think about the great development environment it's built into. If you learn E-Lisp, not only can you start doing interesting things from day 1, you gain better command of a useful tool even if you later decide not to continue with Lisp.
There are a number of other homoiconic languages floating about so I think that's much less an issue other than the fact that "lisp" is the poster child.

Alas, CL is an old, bloated nightmare. :-( :-)

I think the new poster child for "Lisp" is Clojure.

Also, for learning programming, I'm still a big fan of Scheme.

Agree about Clojure. The main reason I didn't choose it is that I thought a good Perlis language should not require learning much that wasn't directly related to using the new paradigm. With Clojure, you have the whole Java platform to deal with as well.

Of course, there are tons of Java programmers out there and several really interesting languages for the JVM. I have thought that there should really be a list similar to mine, for people who are already working in the Java environment.

I'd go for Scheme or even Factor for code-as-data. (Joy, Factor's ancestor, is really code-as-data, and unlike Emacs Lisp it's hygienic because there are no variables. Scheme also has the most Perlis-ish macros.

I think either J or K is better than APL in this category.

I would also add Pure <http://pure-lang.googlecode.com>; for general term rewriting (lambda calculus? Just a special case!)

I see your point about Scheme. I had wanted to stay with a Lisp, since the Scheme family has a different orientation, with the emphasis on functional techniques among other things. But maybe the more powerful macro system would justify the extra learning load.

I would need some convincing with J, though. I've studied both and I thought APL had much better tutorial material, development tools, and conceptual straightforwardness. I didn't stick with J for very long, so I'm sure I missed important aspects of its use. Could you explain some ways in which you think J gives a better demonstration of the possibilities of the array-oriented paradigm?

I think more people would give Pure a try if it wasn't advertised primarily as a term rewriting language.

Pure is a dynamically-typed, eager, impure functional language with Haskell-ish syntax. It also has optional type declarations and forced lazy evaluation. "Term rewriting" is the evaluation model.

More paradigms:

Maude. Pure. OBJ3 - term rewriting

Inform 7 - object-relational

Kaleidoscope. - constraint imperative

Bloom. Dedalus. - Temporal Logic; monotonic data.

Excel. Spreadsheets. - reactive dataflow.

Conway's Game of Life - Cellular automata.

Oz/Mozart - distributed unification.

I would suggest Dedalus (datalog + time) as a cleaner example than Prolog of how to lift logic programming into general purpose computation.