43

I'm trying to define an anonymous function to do a dot product, I can code this as a private function without any problem but I am struggling with the anonymous function syntax. I know I could implement this differently but I am trying to understand how to define anonymous functions with pattern matching and recursion. This is my current implementation

dot = fn
  [i|input],[w|weights], acc -> dot.(input,weights,i*w+acc)
  [],[bias],acc -> acc + bias
end

And I get this error on compile:

function dot/0 undefined

Any hints? Is this just not possible?

2
  • // , Excellent question, Batou99. Do you know if there's anything about this, specifically, in the Elixir documentation? Might be a good candidate for the FAQ page. Commented Sep 15, 2015 at 22:08
  • Not as far as I know. But José Valim added some comment about this may be changing due to changes in Erlang 17, we are now at Erlang 18 so this definitely may have changed already. Commented Sep 22, 2015 at 11:52

5 Answers 5

44

It is not possible to recur on anonymous functions in Elixir.

Erlang 17 (currently a release candidate) adds this possibility to Erlang and we plan to leverage it soon. Right now, the best approach is to define a module function and pass it around:

def neural_bias([i|input],[w|weights], acc) do
  neural(input,weights,i*w+acc)
end

def neural_bias([], [bias], acc) do
  acc + bias
end

And then:

&neural_bias/3
Sign up to request clarification or add additional context in comments.

10 Comments

Does elixir now support recursing anonymous functions?
Not yet, we had plans but we couldn't agree on a syntax so it has been postponed to after 1.0.
@JoséValim where could we follow debates about this subject ?
As noted here it is possible to define a recursive function using only anonymous function using the excellent fix point combinator (Y combinator). Though I guess the asker was expecting first class language support without having to use Y.
@JoséValim Has this been added yet?
|
44

The less formal but still acceptable approach is:

factorial = fn
  (0,_) -> 1
  (1,_) -> 1
  (n, fun) -> n * fun.(n - 1, fun)
end

You call it with factorial.(6, factorial) # 720

2 Comments

That's kind of like PHP's &referencing style.
Ha 🤯 I love this. Feels kinda evil!
14

Here's a fixed (Y) combinator:

fix = fn f -> 
    (fn z ->
        z.(z)
    end).(fn x -> 
        f.(fn y -> (x.(x)).(y) end)
    end)
end

Here's how you use it:

factorial = fn factorial ->
    fn
        0 -> 0
        1 -> 1
        number -> number * factorial.(number - 1)
    end
end

fix.(factorial).(6) # 720

Only works with functions that recurse with 1 argument. Elixir doesn't have variable arguments. To support multiple arguments, you'll need to add more arguments than the single y like: f.(fn a,b -> (x.(x)).(a,b) end).

1 Comment

I would call the original function factorial_stub and factorial = fix.(factorial_stub). Simple change but makes it a little clearer to first timers IMO.
3

You could define a module-function called fix, and use it later to define dot (and any other recursing anonymous function):

defmodule A do
    def fix(f, x) do
      f.(fn(x) -> fix(f, x) end, x)
    end

    def fix2(f, x, y) do
      f.(fn(x, y) -> fix2(f, x, y) end, x, y)
    end
end

dot = fn(x, y) ->
    A.fix2(fn
          dot, [i|input],[w|weights], acc -> dot.(input,weights,i*w+acc)
          dot, [],[bias],acc -> acc + bias
    end, x, y)
end

4 Comments

Is this the y-combinator?
Essentially, a fixed-point combinator: en.wikipedia.org/wiki/Fixed-point_combinator
I see that there is fix1 and fix2, can there be a single fix or any number of arguments?
@CMCDragonkai I'm not using Elixir anymore, and it has changed a lot since I stopped. You should open a new question if you'd like to get an answer to that.
1

Constructing on @hamiltop answer, if you don't to always pass the fn yourself during calls, you can then wrap it:

factorial_rec = fn
  (0,_) -> 1
  (1,_) -> 1
  (n, fun) -> n * fun.(n - 1, fun)
end

factorial = fn n ->
  factorial_rec.(n, factorial_rec)
end

So you can call it as factorial.(6)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.