【问题标题】:Recursion and anonymous functions in elixirElixir 中的递归和匿名函数
【发布时间】:2014-03-25 19:37:24
【问题描述】:

我正在尝试定义一个匿名函数来做一个点积,我可以将它编码为一个私有函数而没有任何问题,但我正在努力使用匿名函数语法。 我知道我可以以不同的方式实现这一点,但我试图了解如何使用模式匹配和递归来定义匿名函数。 这是我目前的实现

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

我在编译时收到此错误:

function dot/0 undefined

有什么提示吗?这是不可能的吗?

【问题讨论】:

  • // ,很好的问题,Batou99。你知道是否有任何关于此的内容,特别是在 Elixir 文档中?可能是常见问题解答页面的不错候选者。
  • 据我所知没有。但是 José Valim 补充说,由于 Erlang 17 的变化,这可能会发生变化,我们现在是 Erlang 18,所以这肯定已经发生了变化。

标签: recursion anonymous-function elixir


【解决方案1】:

Elixir 中的匿名函数不可能递归。

Erlang 17(目前是一个候选版本)为 Erlang 添加了这种可能性,我们计划很快利用它。现在,最好的方法是定义一个模块函数并传递它:

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

然后:

&neural_bias/3

【讨论】:

  • 是的。这只是一个例子,它也可以作为一个私有函数。
  • elixir 现在支持递归匿名函数了吗?
  • @JoséValim 我们在哪里可以关注关于这个主题的辩论?
  • here 所述,可以使用出色的定点组合器(Y 组合器)仅使用匿名函数来定义递归函数。虽然我猜提问者期待一流的语言支持而不必使用Y
  • @JoséValim 这个添加了吗?
【解决方案2】:

不太正式但仍然可以接受的方法是:

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

你用factorial.(6, factorial) # 720调用它

【讨论】:

  • 这有点像 PHP 的 &reference 风格。
【解决方案3】:

这是一个固定的 (Y) 组合子:

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

这是你如何使用它:

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

fix.(factorial).(6) # 720

仅适用于使用 1 个参数进行递归的函数。 Elixir 没有可变参数。要支持多个参数,您需要添加比单个 y 更多的参数,例如:f.(fn a,b -> (x.(x)).(a,b) end)

【讨论】:

  • 我将调用原始函数factorial_stubfactorial = fix.(factorial_stub)。简单的更改,但让 IMO 初学者更清楚。
【解决方案4】:

您可以定义一个名为 fix 的模块函数,然后使用它来定义 dot(以及任何其他递归匿名函数):

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

【讨论】:

  • 这是 y-combinator 吗?
  • 本质上是一个定点组合器:en.wikipedia.org/wiki/Fixed-point_combinator
  • 我看到有fix1和fix2,可以有一个fix或者任意数量的参数吗?
  • @CMCDragonkai 我不再使用 Elixir,自从我停止使用它之后,它发生了很大变化。如果你想得到答案,你应该打开一个新问题。
【解决方案5】:

或者,您可以将您的函数传递给 Stream.cycle 以创建“无限循环通过给定枚举的流”。并将其通过管道传递到执行无限流函数的 Enum.each 调用中。

test = spawn fn -> [fn -> receive do: (x -> IO.puts x * 2) end] |> Stream.cycle() |> Enum.each(fn f -> f.() end) end 
#PID<0.161.0>
iex(24)> send test, 1 
1 
2 
iex(25)> send test, 1 
1 
2 
iex(26)> Process.alive?(test) 
true

【讨论】:

    猜你喜欢
    • 2022-06-20
    • 2018-07-09
    • 2011-07-17
    • 2011-10-24
    • 2015-11-21
    • 2011-01-29
    • 2011-04-22
    • 2020-09-24
    • 1970-01-01
    相关资源
    最近更新 更多