Reputation: 1299
I'm trying to learn Erlang, coming from a C++/Java background. This forces me to re-think all my methods.
Right now I'm trying to write something that returns the N first elements of a list. Right now it looks like this, although I can't call functions in guards or if expressions. What is the Erlang way of doing this?
take([Xh|Xr],N,Xn) ->
if
len(Xn) /= N -> take(Xr,N,app(Xh, Xn));
len(Xn) == N -> Xn
end.
I also tried calling the function before, but that didn't work either:
take([Xh|Xr],N,Xn) ->
G = len(Xn);
if
G /= N -> take(Xr,N,app(Xh, Xn));
G == N -> Xn
end.
Upvotes: 4
Views: 520
Reputation: 18859
Your approach isn't wrong per se, it just needs a bit of help:
-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].
As other people hints, your approach is not very Erlang idiomatic, and the other solutions are far better. Also, look up the source code for lists:split/2
https://github.com/erlang/otp/blob/master/lib/stdlib/src/lists.erl#L1351
Upvotes: 0
Reputation: 5327
In addition to Fylke's solution, there is also something to be said for a body recursive approach:
take(_List,0) ->
[];
take([H|T],N) ->
[H|take(T,N-1)].
Upvotes: 4
Reputation: 1836
Generally with this kind of problems, you need to switch to a recursive way of thinking instead of the iterative approach you're using. Here's what I would do:
take(List, N) ->
take(List, N, []).
take(_List, 0, Acc) ->
lists:reverse(Acc);
take([H|T], N, Acc) ->
take(T, N - 1, [H|Acc]).
It's really common for people coming from languages that promote the iterative approach to try and shoehorn that approach into Erlang. The problem is that Erlang doesn't have the primitives for doing it that way since it's a functional language. So you're forced to do it the functional way, and in the end it's often the more elegant approach.
Upvotes: 5