📜 ⬆️ ⬇️

A little bit about Erlang syntax

Initially, I planned to release this opus as an addition to the book “ Learn You Some Erlang ”, but its content is more in line with the editorial material than a good reference document, so I decided to just write about it in a blog.

Many newcomers to the world of Erlang successfully study it and begin to play, without entering into close contact with him. I read a lot of complaints about the syntax and these “goat balls” ( ant turds - orig.) Are a “fun” way to call the characters ,, ; . . For example, "How are they besyat", and much more.

I mentioned in the book that Erlang originates from Prolog. This makes us understand where all these punctuation marks come from, but this, alas, does not make people imbued with love for such punctuation. And really, for some reason, no one says to me: “Oh! Prolog! Well, you have not said it before! ”In view of this, I propose three possible ways of human reading the Erlang code in order to make the world kinder.

Template


My favorite. In order to comprehend this method, you need to stop looking at the code as a set of lines and start thinking in Expressions. An expression is any piece of code that returns something.
')
In the Erlang command line, a period ( . ) Sign indicates the end of an expression. To execute the expression 2 + 2, you need to put a period (and then press Enter) so that it runs and returns something.
However, when writing a module, the dot symbol ends the Forms. Forms are attributes of a module or function declaration. The form returns nothing and therefore is not an expression.

In view of these features, one can argue long about the use of the dot ( . ). But I propose to score on the command line and not use this method in it, but instead remember that the dot must complete the form.

But we will continue. We need two more rules:
  1. A comma ( , ) separates the expression:
    C = A+B, D = A+C 

    Just like a nut, is not it? Note, however, that
     if ... end case ... of ... end begin ... end fun() -> ... end try ... of ... catch ... end 
    - all the essence of the expression. For example, you can do the following:
     Var = if X > 0 -> valid; X =< 0 -> invalid end 
    And get the value of the output if ... end. This explains why we sometimes see commas ( , ) after these language constructs - it just means that we have another expression that needs to be followed.
  2. The semicolon ( ; ) performs two functions.
    1. It shares the various definitions of the function:
       fac(0) -> 1; fac(N) -> N * fac(N-1). 

    2. It separates the various branches of if ... end, case ... of ... end and other expressions:
       if X < 0 -> negative; X > 0 -> positive; X == 0 -> zero end 

      It may seem strange that the last branch of the expression is not separated ( ; ). But after all ( ; ) shares branches, but does not finish each of them. It is necessary to think in expressions, but not in lines. Some people find it easier to read the code if the delimiter is set as follows:
       if X < 0 -> negative ; X > 0 -> positive ; X == 0 -> zero end 

      Such formatting emphasizes the role of ( ; ) as a separator better. This sign goes between the branches and the conditions, and not after them.



Summarizing all the above, we can safely conclude that if a comma ( , ) follows after an expression (for example case ... of ... end), then the following expression must go. The semicolon ( ; ) is placed at the end of the function branch, and the period ( . ) On the last function branch.

Our usual view, when we separated the lines (as, for example, in C or Java) with the ( ; ) symbol, now we just need to take it and throw it out the window. Instead, we view our code as a fillable pattern (hence the name of the method):
 head1(Args) [Guard] -> Expr11, Expr12, …, Expr1N; head2(Args) [Guard] -> Expr21, Expr22, …, Expr2N; headM(Args) [Guard] -> ExprM1, ExprM2, …, ExprMN. %%  ExprIJ -   

These rules really work, but you need to switch your brain to a different code reading mode. This is where the most difficult transition lies: we have to move from lines and blocks to a predefined pattern. Let me explain: if you think about it, then designs like
 for (int i = 0; i >= x; i ++) { … } //   for (...); 
have a very strange syntax compared to many other constructs in other languages. Simply, we are so accustomed to such facilities that we perceive them quite calmly.

Sentence


Not my favorite way, but I understand perfectly well that people perceive logical constructions differently. In addition, this method is often praised.

Here we compare Erlang and language (it is possible English, it is possible Russian). Imagine that you make a list of things to travel. Although no, we will not submit, here it is:
      :   ,    , , ;   ,  , ;   ,   , . 

If you translate it into the Erlang language, then everything will look very similar (Unfortunately, in this form it will not work, because Erlang only supports UTF within string variables, but not the source code. There, in the old manner, ISO-latin -1. - approx. Lane.)
 () -> , , ; () -> , ; () -> , . 

See, you can just replace items with expressions and here it is! But expressions like if ... end should be simply presented as nested lists of such things.

And, Or, End


Another way I was offered on #erlang. In this method, having seen ( , ), it is necessary to read “AND”, ( ; ) becomes “OR” (alternatively, “A MORE”, - note of the translation), and ( . ) Means “END”. Thus, the function declaration can be read as a set of nested logical predicates and conditions.

Finally...


It is extremely difficult for some to accept “goat balls” for the impossibility of taking corners and swapping two lines of code without changing them. It seems to me that many ways to interpret a language at the human level are hard to come up with (and hardly necessary), but I hope this article will prove useful to someone. In the end, "the syntax is not complicated, it just scares."

Source: https://habr.com/ru/post/258537/


All Articles