Elm syntax in elixir

But they do not have top-level pattern matches, and I refuse that extra layer of case/match that is necessary… It is so noisy.

let someFunction = function
  | 42, _ -> "You passed in a 42!  Ignoring the second element"
  | x, str when x>10 -> "Your number is greater than 10 and not 42, and your string is: " ^ str
  | x, str -> "Your number is less than or equal to 10, and your string is: " ^ str

In Erlang/Elixir you pattern matching is linear and the functions have to be together, it is not that different in OCaml. Except OCaml will even tell you when you match is not exhaustive based on the types you accept, or you can mark it to throw an exception on a nomatch. ^.^

EDIT: For example, leaving out that last line gives this warning:

Warnings: File "testing.ml", line 1, characters 19-173:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
(0, _)
(However, some guarded clause may match this value.)

Plus I get nice squiggly lines showing it all in both atom and emacs. ^.^

1 Like

As I said, missing top level pattern match…

This seems like somewhat of a nitpick. Syntactically it’s not “top level”, but conceptually the first entry point in the function will do pattern matching. For all you know, it all just compiles down to the same conceptual matching as Erlang/Elixir.

I used to care about it (the pattern matching) not being as intuitive as Erlang/Haskell, but the only thing it means is that you’ll have your matches one indentation deeper.

Can you elaborate what do you mean by that? I think that OCaml example translate roughly to

def someFunction(42, _) do
  "You passed in a 42!  Ignoring the second element"
end

def someFunction(x, str) when str > 10 do
  "Your number is greater than 10 and not 42, and your string is: #{str}"
end

def someFunction(x, str) do
  "Your number is less than or equal to 10, and your string is: #{str}"
end

And to be honest I think OCaml is more readable (at least for those online function bodies) for me and does exactly the same job, more over let you patter match everything you can in Elixir. And I’d really would like to learn OCaml, and so far one thing that stops me from doing this is that it doesn’t have OTP and so easy and powerful concurrency model, and that’s where aim when it comes to my programming future. :slight_smile: And that does not mean that I think that one or the other is better from syntactical point of view. Neither is very familiar to me :wink:

Of ocurse it is more readable, but if you really want to translate it to elixir, it is the following:

def someFunction() do
  fn (42, _) -> # stuff
     (x, str) when x > 10 -> # other stuff
     (x, str) -> # fallback stuff
  end
end

OK, I do assume OCaml is properly curried, so I do also assume, that in OCaml in fact there is no semantic difference, but still, I prefer a pattern match on the left hand side of the =, without any additional layer of syntax, as I do have it in erlang, elixir, and haskell, but not in elm, OCaml or Rust.

Do you think fn -> end and def end noisy? I think mostly def end is OK but I hate fn -> end. To me it’s kind of a trade-off like the difference of binding once/rebinding in Erlang and Elixir. You got top-level pattern match but you lose the convenience of easy function declaration.

Yeah! I still have my MC68000 programming reference card! Wow, that brings back memories!

Erlang/elixir is the same way though, just one indention level up. You still have to keep your function heads together and in the order that you want them tested. :wink:

Precisely. ^.^
You can separate the cases with newlines if you want, you can even move them up without indentation if you want to too (OCaml is not whitespace sensitive unlike Haskell:

let someFunction = function

| 42, _ -> "You passed in a 42!  Ignoring the second element"

| x, str when x>10 -> "Your number is greater than 10 and not 42, and your string is: " ^ str

| x, str -> "Your number is less than or equal to 10, and your string is: " ^ str

Or you can even define the types that everything accepts in the ‘head’ too:


let someFunction : int * string -> string = function

| 42, _ -> "You passed in a 42!  Ignoring the second element"

| x, str when x>10 -> "Your number is greater than 10 and not 42, and your string is: " ^ str

| x, str -> "Your number is less than or equal to 10, and your string is: " ^ str

No, actually the example you gave in Elixir would be like this in OCaml:

let someFunction(x, str) =
  match x, str with
  | x, str when x > 10 -> "blah"
  | x, str -> "blee"

There are some functional differences between them.

It is properly curried, but it also uncurries in the (f)lambda compiler. You can match before the = too, but only once:

let someFunction 10 str = "This function only accepts a '10' for its first arg, your second is: " ^ str

That is why the function keyword exists, it gives a top level matching context (near identically to how erlang does it internally too).

Remember that everything is an expression. If you wanted to have syntax like:

let blah 10 = "blah"
let blah 15 = "blorp"
let blah x = string_of_int x

Well each is defining its own variable in the context, and as the context is updated as it is built you get a new definition because in OCaml you can redefine functions (think an implicit defoverridable in elixir terminology, thus to have a top level match context you have to state that you are doing it some-how. Even in both erlang and elixir I rarely do multiple top-level function heads but rather do an internal case on a single one. Makes it easier to reason about especially in elixir with optional arguments, default arguments, etc…

As a comparison, haskell also does not have the ability to redefine functions, it is one of the things in the language that is odd, because you can define new scopes in haskell that redefine something, yet not to top level functions, it is an inconsistency and one of the reasons it is white-space important. The top level context of OCaml is no different than any other context in any other location except the in is optional, so I could just as easily define the above inside a function and use it too, like this:

let someOuterFunction x =
  let someFunction = function
  | 42, _ -> "You passed in a 42!  Ignoring the second element"
  | x, str when x>10 -> "Your number is greater than 10 and not 42, and your string is: " ^ str
  | x, str -> "Your number is less than or equal to 10, and your string is: " ^ str
  in someFunction x "blah"

Yeah Erlang is the same way. I prefer function definitions that follow the same format everywhere (which OCaml does).

That was it! Oh I programmed so much on that thing! That is an assembly chip worth working on! ^.^

1 Like

i think that more than compiling, the ELM abstraction approach could also be translated, and the idea of Message, command, etc… added to a gen_server would be great

1 Like

I believe this is solved by @Qqwy’s GenFRP library?

2 Likes

We now have a thread dedicated to syntax preferences:

https://elixirforum.com/t/discussion-about-syntax-preferences-split-posts/3436

I’m closing this one to direct all syntax-preference discussions there :slight_smile:

2 Likes