Functions
Anonymous Functions
p = fn x -> IO.puts(x) end
is_function(p)
# arity
is_function(p, 0)
# arity
is_function(p, 1)
# arity
is_function(p, 2)
p.("Hello world!")
(fn x -> x + 1 end).(7)
(fn x ->
y = x + 2
z = y - 1
z
end).(7)
# Would be reformated to multiple lines. Lol it did it automatically?
# What I meant to demonstrate was that ";" could be used instead of "\n"
(fn x ->
y = x + 2
z = y - 1
z
end).(7)
(fn x ->
IO.puts(x)
:ok
end).("Dude!")
adder = fn x -> fn y -> x + y end end
add7 = adder.(7)
add7.(8)
And now an even more compact / agressive syntactic version of anonymous functions. (Limitations: no constant function, single-expression only (no blocks)).
# needed since f = IO.puts would CALL the function
f = &IO.puts(&1)
f.("Hello!")
add = &(&1 + &2)
add.(2, 3)
# Issue here for closure to disambiguate the argument
adder = &(&(&1 + &2))
# -> nested captures are not allowed which makes sense. So this notation may
# be handy but it is also a bit cryptic and is less general than `(fn -> ... end)`.
Named Functions
# 🙁
def p(message) do
IO.puts(message)
end
defmodule Utils do
def p(message) do
IO.puts(message)
end
def g() do
IO.puts("---")
end
end
p("Hello!")
Utils.p("Hello!")
import Utils
p("Hello!")
# wow. Function of arity 0 called !!!
# Not what was intended (by me),
# but consistent wrt the optional nature of parentheses in function call
f = Utils.g()
# Mmm does it mean that there are not "public constants" in Module
# or do we have the same syntax that can mean two different things here?
# f is now an unnamed function
f = &Utils.f/1
Question: I am a bit fuzzy about what the need to specify arity means here. Probably:
- Functions with different arity within a module are considered as not related (the common name is considered “an accident” by the VM)
- What does it mean for functions with default arguments. Are they expanded to functions with different arities and then does it mean that we can’t capture them as anonymous functions?
f.("Hello world!")
🚧 TODO: end of the concepts in
Arity, Guards & Default Values
# Fuuuuuck. Default values only work for named functions.
f = fn x, y \\ 0 -> x + y end
defmodule Utils do
def add(x \\ 0, y \\ 0, z \\ 0) do
x + y + z
end
end
Utils.add()
Utils.add(1)
Utils.add(1, 2)
Utils.add(1, 2, 3)
add = &Utils.add/0
add.()
OK, the stuff with default values is effectively compiled to several distinct Erlang functions.
defmodule Utils do
def fact(n \\ 0)
def fact(n) when n == 0 do
1
end
# else
def fact(n) do
n * fact(n - 1)
end
end
import Utils
fact()
fact(10)