Hi guys!
Recently I learned Elixir and now I’m rewriting my project in it. This language is great and really fun to use.
And I found there are some “if I could do this” things.
So I played with my virtual syntax as below:
- Keyword syntactic sugar
# inspired by ECMAScript:
# const { a, b, c } = { a: "A", b: "B", c: "C" }
# const obj = { a, b, c }
:[foo, bar, baz]
# (SyntaxError)v1.6.2, expect it to be interpreted as
# => [foo: foo, bar: bar, baz: baz]
# With multiple keywords, we could do
foo, bar, baz
# => [foo: foo, bar: bar, baz: baz]
# `foo` is `foo` and would have to use `:[foo]` to be `[foo: foo]`
# In that case, we must be careful not to involve neighbouring
Foo.start_link state, i, short, very_long_keyword
# Gatcha! => Foo.start_link [state: state, i: i, short: short, very_long_keyword: very_long_keyword]
Foo.start_link state, :[i, short, very_long_keyword]
# => Foo.start_link state, i: i, short: short, very_long_keyword: very_long_keyword
# In function params, we would have to use :[] style
def foo(:[bar, baz]), do: something bar, baz
# for Map
%{foo, bar, baz}
# => %{foo: foo, bar: bar, baz: baz}
# Struct
def to_person(%Plug.Conn{assigns: %{name, age, bio, phone, address}}) do
%Person{name, age, bio, phone, address}
end
# pattern matching
i, short, very_long_keyword: long = [i: 42, short: "ex", very_long_keyword: "elixir-lang"]
# would match: i = 42, short = "ex", long = "elixir-lang"
# nested
foo, bar, baz: %{a, "b" => b} = [foo: "FOO", bar: "BAR", baz: %{a: "A", "b" => "B"}]
# would match: foo = "FOO", bar = "BAR", a = "A", b = "B"
- Guard syntactic sugar
def foo(bar) when is_integer, do: bar + 1
def foo(bar) when is_float, do: trunc(bar) + 1
def foo(bar) when is_binary, do: do_binary(bar)
# (ArgumentError) v1.6.2 =>
# def foo(bar) when is_integer(bar), do: ..
# def foo(bar) when is_float(bar), do: ..
# def foo(bar) when is_binary(bar), do: ..
# Guard without argument means "catch whole arg"
# but would make sense only with foo/1 function..
- Piping extension
# Acceptance of anonymous function
9
|> Foo.plus(1)
|> &Foo.div(1000, &1)
|> &"result is #{&1}"
# (ArgumentError) v1.6.2 =>
# 9
# |> Foo.plus(1)
# |> (&Foo.div(1000, &1)).()
# |> (&"result is #{&1}").()
# "result is 100"
# Create anonymous function by headless piping
my_func = |> Foo.plus(1) |> &Foo.div(1000, &1) |> &"result is #{&1}"
# (SyntaxError) v1.6.2 =>
# my_func = fn i -> i |> Foo.plus(1) |> (&Foo.div(1000, &1)).() |> (&"result is #{&1}").() end
# Gatcha!
def get_my_func() do
one = 1
thousand = 1000
|> Foo.plus(one) |> &Foo.div(thousand, &1) |> &"result is #{&1}"
end
# would result in normal piping: `1000 |> Foo.plus(..) ..`
I know these would likely increase confusion especially to new comers.
It’s just playing, thanks!