Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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

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).

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

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)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top