That reference helps the original link make a lot more sense.
I've spent about 2.5 years of my career writing Erlang code. It's statements like "Core Erlang is less complicated than Erlang" that always trouble me about the Erlang community - Core Erlang is less complicated for compilers, not for humans. In this first in a series of blog posts about Core Erlang, there is no context given around what it is or why anyone should care.
Erlang is a great language and environment, but it really struggles with the marketing aspects of a platform, that is, how to make it accessible to humans.
It's a hallmark of slow moving platforms: the investment in time is such that by the time you need something like Core Erlang you will know exactly where to place it. Erlang is not exactly beginner friendly (in spite of some effort in that direction) and it is a strange beast in many ways compared to what counts for 'modern'. Even so it has stood the test of time well and embodies a lot of the things that people are - reluctantly - rediscovering in its foundation rather than as belated add-ons.
Agreed, Erlang is surprisingly simple and concise. It's pretty straightforward how you'd design any particular piece of code.
The only complexity is figuring out OTP, which in itself is very easy to use, but you must understand all the underlying abstraction it's masking before really being good at it.
Once you get familiar with the boilerplate of distributed systems and see how OTP helps eliminate much of it, with a best-practice design figured out for you, that's when you really start to respect Erlang.
Of all the languages I've learned on the side I think Erlang/OTP has the most amount of features I feel are missing from other languages (proper pattern matching being the biggest).
They're similar in what they are used for, but they come from different traditions and so have some differences.
F# patterns come from ML, with active patterns added on top. Erlang patterns come from Prolog, with unification removed.
A quick example, in Erlang you can write:
1> (X = {1 = A, [2, 3]}) = {1, [2, 3]}.
{1,[2,3]}
As well as:
1> ({A = 1, [2, 3]} = X) = {1, [2, 3]}.
{1,[2,3]}
That is, the `=` is actually a pattern matching operator and the order of its two operands doesn't matter (well, not really, not everywhere - that's where the "removed unification" comes from - but close enough). That's because in Prolog the `=` operator denotes actual equivalence, not an assignment, and Erlang inherited that.
In F# and OCaml this is done with a special operator, `as`, and it cares about the order of its operands very much. You can do this:
> let (1 as a, [2; 3]) as x = (1, [2; 3]);;
val x : int * int list = (1, [2; 3])
val a : int = 1
but
> let (a as 1, ...etc
obviously won't work.
All in all, both mechanisms work quite well and you can translate between them easily, but they are not 100% equivalent. Erlang has much simpler syntax (it's basically just `=`) while F# adds `as`, `&` and other constructs. In Erlang, once a name is matched with an expression, it is equivalent to that expression and stays that way forever. In OCaml, you can readily reassign matched names. That also makes Erlang pattern matching act like an assert and (identity) comparison in some situations, which are both different things in F#.
So, the use-cases are very similar, but the concepts underlying the mechanisms differ which in turn makes some details of the mechanisms differ too. Both are a joy to work with, to be sure, compared to the "applied ifology" or the dreaded `switch` statement, though :)
Yep, Erlang's use of = operator's pattern matching / assignment allows for some very elegant solutions, in addition to function guards, deconstruction, and other use-cases.
It basically uses pattern matching as a fundamental/primitive part of the language design, rather than some useful add-on or tertiary feature.
That still repeats the `Total - N` 3 times, though. As patrec said, it's possible to work around this with guards in this specific case, but in general this kind of duplication is indeed common in Erlang code. You can avoid it many cases by correctly factoring the code, but it's not always possible and then it's a bit irritating. Not too much, though. It's basically the difference between fall-through and non-fall-through `switch` statement: OCaml/F# allow fall-through (as an option, not by default, thankfully), Erlang/Elixir/LFE don't.
I started playing around with Elixir a while back and find it really fascinating as a language.
I've been a Scala dev for years and I gradually learned FP by moving from Java to Scala, but in the case of Elixir, I've only barely looked at some Erlang previously.
Would you say Elixir has done a better marketing job of being accessible to developers?
Elixir has pretty solid marketing indeed but IMO the tooling is what really makes it shine. Hex and Mix are the simplest, cleanest and most straightforward tools I ever used for 16 years of career. Add OTP, friendly syntax and mature runtime to the mix and IMO Elixir is right now unbeatable in the realm of dynamic compiled languages.
Marketing is better than Erlang (not difficult: http://erlang.org/doc/man/lists.html), but also it stacks up to some analysis rather than just being hype. Largely due to it being based on Erlang but also developer friendliness (build tool, docs, security, setup, simplicity) is really second to none for a compiled language.
I think it's not so much marketing as developer experience, and tooling. As a sibling post mentions, Mix and Hex are amazing. Mix new is a very nice gateway into a new project, giving you a fully working setup and even setting up the basics of a supervision tree, if you want it. Beyond that, it makes some less approachable aspects of OTP much simpler for a newcomer to use. Once you get the basics, Genservers are very nice to work with.
The stdlib is also a strong selling point of Elixir. Agent and Task modules are a nice addition. AFAIK they have no equivalent in Erlang stdlib. It's trivial to implement them on top of gen_server, but that's it - you need to reimplement them every time, while in Elixir you have them available by default. DynamicSupervisor is similarly a nice(r) interface to simple_one_for_one supervisors.
In terms of language features, Elixir gives you (almost first-class) modules, protocols, and macros. They are all implementable in Erlang, for example qlc is a DSL implemented with parse transforms (which are macros), but Elixir gives them to you nicely packaged and ready to use.
It can also become a problem. I love Lisps, and love proper macros, but every other macro I see written by Elixir guys makes me cringe. Macros are a powerful tool and it takes time and effort to learn not to abuse them. In Lisps, even the younger ones, like Clojure, people only write macros if there's really no other way to do something. In Elixir, people write them for everything, they break hygiene habitually, and the language encourages that (the `use` and `__using__` are the biggest offenders here, IMHO). It's a trade-off between easy-to-write (in Elixir) and easy-to-read-and-debug (in Erlang). Both approaches are valid, but for different use-cases.
I'm not sure I've encountered a context where "less complicated", said of software, implied "easier to use". Siri is fiendishly complex but very easy to use. A brace and bit is less complicated than a power drill, but the power drill is easier to use.
Also, please don't use rhetoric of the form "We need to make software accessible to/usable by humans." If the software is not usable by humans, who exactly is using it? To what species do they belong? Say "new users"/"people unfamiliar with the language"/etc. instead.
This blog entry is part of an ongoing series about the passes in an Erlang compilation. The author probably assumed some familiarity with Erlang itself, and previous entries in the series, not intending this entry for an audience of general unspecified humans. I'm not sure it's the author's duty to turn every technical post they write into newbie-accessible marketing.
But that's what he said: "Core Erlang is less complicated than Erlang, and is therefore more suited than the abstract format for code analyzing tools (such as Dialyzer) and optimizers."
If you're a human, you understand that "less complicated" means easier to use. Since you're a software engineer you must be some sort of bioengineered alien hybrid, for whom words don't hold the clear indisputable meanings they do in the Imperium of Man.
I notice in that article that both Erlang and Elixir become "Erlang Abstract Form" before becoming "Core Erlang". What is the purpose of the abstract form vs. core erlang? Why this intermediate step?
Compilers use many intermediate steps to transform the input on the way to their final destination, in this case bytecode. Each of these 'passes' performs one or more transformations with a specific goal for each transformation (for instance: an optimization). The Erlang Abstract Format is a parse tree representation for Erlang code.
I am not familiar with Erlang, so please forgive my ignorance in advance.
Is Erlang an abstraction on top of Core Erlang? I ask because the later is far more verbose than the former. Is there a performance or extensible benefit to this more verbose and precise form that I am not aware of?
Erlang is the top level user visible language. This gets transformed through several steps to at some point Core Erlang, which ultimately gets transformed into a binary representation that BEAM can interpret.
The only benefit is that it is easier for a machine to do the transformation from Core Erlang to BEAM bytecode than it would be if that machine would have to transform Erlang in one go, similar to how a C compiler will first make a tree like representation of the program in memory, will then convert that tree into some assembly (or a meta assembly language that is still platform independent) which will then be converted to binary. Each of those stages has a corresponding equivalent in the Erlang domain:
Erlang -> C
Abstract Format -> AST
Core Erlang -> Assembler
BEAM Bytecode -> binary
The equivalence is obviously not exact but good enough for this explanation.
It does therefore have a syntax heavily influenced by Prolog.
But that doesn't mean that Prolog was the only incluence. The Erlang case expression for pattern matching doesn't really correspond to anything in Prolog, it does look more similar to ML-family languages. The multi-branch if expression looks like a Lisp cond form and again not that much like Prolog.
https://8thlight.com/blog/kofi-gumbs/2017/05/02/core-erlang....
Core Erlang is an intermediary language targeting 'BEAM', the Erlang virtual machine.