Learning Elixir, frst impressions ( plz don't kill me ! )

Weird is in the eye of the beholder, of course, but let me see if I can explain why this is the case. Elixir uses separate contexts to bind named functions and variables. This, as I understand it, means that Elixir is a “LISP 2” language. Here is a code sample:

defmodule DotSyntaxExample do

  def ambiguous(x) do
    IO.puts("I am in the ambiguous named function #{inspect x}")
  end

  def entry_point() do
    ambiguous = fn (y) -> IO.puts "I am in the ambigous variable. #{y}" end

    ambiguous("Hello")
    ambiguous.("World")
  end

end

DotSyntaxExample.entry_point()

# λ <521>$ elixir Ambiguous.exs
# I am in the ambiguous named function "Hello"
# I am in the ambigous variable. World

In this contrived example, when you are in the context of the entry_point function, there is a binding in the space of named functions for ambiguous and the function itself creates a binding to a variable named ambiguous that happens to lead to an anonymous function.

At the call site I need to tell the system which of the two I am interested in calling, the named function, or the value in the variable. For that reason, Elixir uses the .() syntax to indicate that I want to use the variable binding instead of the named function binding.

2 Likes

What I mean by weird, is that when compared to how you call normal functions in Elixir. Your example illustrates this in perfection:

 ambiguous("Hello")
 ambiguous.("World")

Now I get why you need .() in this example. It is a disambiguation.
However when currying ( in he article I presented and in here ) it seems that the only way to use dynamic functions is to bind them, which results in the syntax .(), instead of the more natural ().

But perhaps I am mistaken? Perhaps there is a way to call anonymous functions when currying that doesn’t require binding ? ( and thus promotes the usage of the () syntax ? )

About your serach at hex.pm, I think the most complete package is https://github.com/expede/witchcraft

1 Like

People seem to forget that a curried function is a workaround for the constraint in lambda calculus that a function can only have one, single argument. So in its original form (((f(1))(2))(3)) was necessary instead of f(1,2,3).

Languages like Haskell and OCaml popularized a notational convenience where you can use forms like f(1) and f(1,2) to return another function. But somehow people conflate that notational convenience with “currying”.

What is worse is that the obsession with currying seems to obscure the fact that “partial application” is the useful and powerful idea - which can be implemented simply by capturing available parameters inside a closure and returning a function that is ready to accept the remaining parameters.

As far as I’m concerned partial application is the meat and potatoes - currying is a mere frill.

11 Likes

These two statements are curious and interesting to me. “Horrible” is obviously a subjective opinion, and, in my opinion, a rather strong superlative to paint the entire API with. I’ve never seen anyone else mention that the the position of parameters in a function call being a “basic concept of FP languages”.

Is it somehow tied into your apparent penchant and desire for partial application?

I’ve not really had any strong problems using the Elixir API. It’s something I do have to think about switching back and forth between Elixir and Elm. Even so, I certainly wouldn’t categorize it as “horrible” myself so I’m genuinely curious to know, what do you find so objectionable?

That topic does come up regularly but because on the BEAM different functions can have the same name as long as the arity differs, creating Haskell-style “compile time notational currying” is basically out of the question anyway.

(In Bucklescript, which supports curried functions, parameter position was an ardently discussed topic).

1 Like

Plus, an additional reason for data-first API in Elixir is consistency with (most of, except a few modules) erlang existing conventions. This is a very pragmatic, down-to-earth consideration, one that in my eyes brings much more value than bikeshedding around not-so-important syntactic preferences. This is a typical example of what I like about the way Jose and the core team are designing things, being pragmatic and resisting the temptation to over-design. In my view, this gives Elixir a credibility that is rare for a young language, the opposite of a toy language or a research-oriented one.

1 Like

Not every FP language is a Haskell-derivative :slight_smile: so it’s odd that you are expecting the same set of features in every FP language. Have you ever tried Idris or ATS for instance? would you say that Haskell is less FP just because its type system lacks linear, uniqueness or dependent types?

1 Like

There is no requirement to bind an anonymous function to a name before it can be invoked:


  def partially_apply_me(left_addend) do
    fn (right_addend) -> left_addend + right_addend end
  end

  IO.puts partially_apply_me(3).(5)

Or simply:

iex(4)> (fn (x) -> IO.puts(x) end).("foo")  
foo
:ok

But in these examples, as well as the one above where the function is bound to a variable the .() syntax is consistently applied to indicate that you are applying parameters to an anonymous function.

It might be that in the partial application case you could unambiguously drop the dot, but then that would then be an inconsistency in the syntax of calling anonymous functions.

1 Like

So why use Elixir ?

If for no other reason – The BEAM! :smile:

That. That right there is worth overcoming any issues you may have with Elixir or Erlang as languages. It’s the Erlang Run-Time System (ERTS) that separates it from the pack.

[mike drop]

3 Likes

So did you accept the job offer of not? Let us know as there are a of people on this forum that find programming in Erlang/Elixir/Phoenix a joy and my guess is many would accept the offer with little hesitation. I know I would ( well if I don’t have to sacrifice a virgin and goat and yada yada yada to get it ).

There is a course that examines different programming languages down to the compiler/interpreter level and goes into details about the trade-offs. It even shows how to create functional like language interpreters using an OOP language and vice versa. It will take about 3 months to go through it but it’s worth it and here is a blurb about it:
https://oleb.net/blog/2014/12/programming-languages-mooc/

Purescript is an example of a language that is transliterated into another language - javascript. I read the book and did the examples and like it a lot - would love a job using it as well - just don’t know if there will ever be much of a demand for it.

Getting into the syntax difference reminds me of the endless flame wars between Ruby and Python and how having to indent code was a horrible thing - well I loved programming in Ruby but anyone can now see that Python is rising to the top of the list of most programming languages used. I now use and enjoy both and they are way more alike than different and syntax is no issue - at least to me.

But you can and I think should should hold out for a job using pure functional languages only - you will never really be enthusiastic about your job if you don’t. Here is a partial list to get you started:

No not really. I think this is one of the biggest warts of the language.

By the way, glancing over this thread, I’m not sure if you really covered what I perceive as a terminology gap. In FP vernacular, a purely functional language is one that captures all side-effects in the type system. There are very few of these: Haskell, Purescript, Idris (notice these compilers are all written in Haskell), a few others. As a Haskeller who writes Elixir for a living, I can tell you that Elixir does disappoint in many ways that you’ve pointed out. But Elixir has other strengths - in particular it is really easy to learn compared to Haskell, and has really great, production-ready libraries for many practical uses that I find lacking in Haskell. Elixir also has a much more coherent standard library - its easy to remember where everything is. When writing Haskell I still hoogle a lot even for base functions, and I’ve been writing it for five years.

2 Likes

Actually - thanks for starting this post because while examining the list of purely functional languages that are also by design intended for concurrent programming I came across this which seems very interesting indeed to me:

1 Like

OTP is the core framework and main value proposition for both Elixir and Erlang. It’s so core it’s part of the kernel. Without OTP Elixir probably doesn’t exist and Erlang is just a weird Prolog variant nobody remembers. It is to Elixir what the DOM is to JavaScript.

On the sidebar: Languages have their purposes and being a pure functional language reference design is not one of Elixir’s. Characterizing Elixir’s diff of Haskell features as a negative or con is misguided and a disservice. Both are functional. Haskell exists to be purely functional at the expense of pragmatism. Elixir exists to be robust, fault tolerant and concurrent at the expense of purity. Being a functional language is a means to an end in Elixir and Erlang, it’s not the reason they exist unlike Haskell. Some of the things you list as negatives are impossible without a static, strongly enforced type system. Elixir has a dynamic, weakly enforced type system.

2 Likes

Yep, took it. I am now reading an Elixir book ( Which book to read? ) and I am starting to think that Erlang / Elixir might have been what I have been looking my whole life as a backend developer but never knew existed.

And now that I made my piece with Erlang / Elixir and see it for what it truly is ( concurrency oriented programming language with some FP features ) I am rather excited :smiley:

This is mainly thanks to Python’s prominence int he field of AI, a battle ruby lost long ago.
Also, nice list, thanks !

This is exactly how I felt. Still, now I want to learn Elixir’s strengths and I think I will love them. I have already starting to read a book and it sure sounds convincing!

As I have stated before, I now understand that my expectations played quite a role here. Now I understand Elixir’s main purpose and I am already on the learning wagon :smiley:

3 Likes

This isn’t quite right. Erlang and Elixir are definitely functional languages. Not inspired by, not functional features, but fully functional. There are no loops, no mutable variables, no “classes” or modular state of any kind. Most imperative techniques are simply not applicable. It isn’t pure, but neither are the lisps, and its more functional than most of them.

4 Likes

Actually:

4 Likes

Well, let’s just agree to disagree then. No worries, we can still be friends :stuck_out_tongue:

Now this is an interesting turn of events :smiley:

There is no disagreement. I’m simply explaining how these terms are used in computer science and in industry. If you want to use them differently after knowing that, its fine with me.

5 Likes

The with keyword used with pattern matching on success and error (e.g. {:ok, value} and {:error, error}) tagged tuples could be considered as Elixir’s built-in equivalent to the maybe monad.