基本Erlang-guards等中函数调用的替代方案

基本Erlang-guards等中函数调用的替代方案,erlang,Erlang,我试图学习Erlang,来自C++/Java背景。这迫使我重新思考我所有的方法 现在我正在尝试写一些东西,返回列表的前N个元素。现在看起来是这样的,尽管我不能在guards或if表达式中调用函数。Erlang的方法是什么 take([Xh|Xr],N,Xn) -> if len(Xn) /= N -> take(Xr,N,app(Xh, Xn)); len(Xn) == N -> Xn end. 我以前也尝试过调用该函数,但也没

我试图学习Erlang,来自C++/Java背景。这迫使我重新思考我所有的方法

现在我正在尝试写一些东西,返回列表的前N个元素。现在看起来是这样的,尽管我不能在guards或if表达式中调用函数。Erlang的方法是什么

take([Xh|Xr],N,Xn) ->
    if
        len(Xn) /= N -> take(Xr,N,app(Xh, Xn));
        len(Xn) == N -> Xn
    end.
我以前也尝试过调用该函数,但也没有成功:

take([Xh|Xr],N,Xn) ->
   G = len(Xn);
    if
        G /= N -> take(Xr,N,app(Xh, Xn));
        G == N -> Xn
    end.

一般来说,对于这类问题,您需要切换到递归思维方式,而不是使用迭代方法。下面是我要做的:

take(List, N) ->
    take(List, N, []).
take(_List, 0, Acc) ->
    lists:reverse(Acc);
take([H|T], N, Acc) ->
    take(T, N - 1, [H|Acc]).

对于来自提倡迭代方法的语言的人来说,尝试将这种方法硬塞进Erlang是很常见的。问题是Erlang没有这样做的原语,因为它是一种函数式语言。因此,您不得不以函数式的方式进行操作,最终这通常是一种更优雅的方法。

除了Fylke的解决方案外,对于身体递归方法也有一些说法:

take(_List,0) ->
  [];
take([H|T],N) ->
  [H|take(T,N-1)].

你的方法本身并没有错,只是需要一些帮助:

-module(foo).
-compile(export_all).

take([Xh|Xr],N,Xn) ->
    G = length(Xn), %% This line had trouble. Use length/1 and end with , not ;
    if
        G /= N ->
          take(Xr,N,app(Xh, Xn));
        G == N ->
          Xn
    end.

app(X, L) ->
    L ++ [X].
正如其他人所暗示的,您的方法不是非常地道的Erlang,其他解决方案要好得多。此外,还可以在源代码中查找列表:split/2


这个问题实际上与有一些更明确答案的问题相同。我认为这是一种递归的解决方法,只是增加了一个条件。嗯,我想我还没有开始思考。谢谢它是递归的,因为你在调用你自己,但是你在向上计数而不是向下,这就是为什么我称它为迭代的。这使得确定何时到达基本情况变得更加困难。我知道“\u”可以标记一个无关变量,但它在这个意义上做了什么,就像在“\u列表”中一样?它标记一个命名的无关变量。关键是,你可以提示读者,我们在那个位置取一个列表,而不仅仅是一些东西。Erlang内部成员也以同样的方式对待它们。@Rickard它通常被称为不关心变量,因为它肯定不是不相关的,因为它必须存在,但我们不关心它有什么值。
\u
变量从不绑定到某个值,因此它可以在模式中多次使用而没有意义。通常,当您仅绑定变量而不使用它时,编译器会发出警告,但是如果变量以“u”开头,如上面的
\u列表中所示,则不会发出此类警告。注意,这样的变量是一个普通变量,在任何方面都是一个普通变量,只有
\uu
在语言中是真正特殊的。