Picture by Sarah Inteman/John Kiehl
This function takes an integer as its first parameter and then any other term as its second parameter. It will then create a list of as many copies of the term as specified by the integer.
Module name and interface
--module(duplicate) --export([duplicate/2])
Function parameter is going to be something like this
a function that calls itself
duplicate(X, Term) when X > 0 -> [Term | duplicate(X-1,Term)].
duplicate(0, _) -> []; duplicate(X, Term) when X > 0 -> [Term | duplicate(X-1,Term)].
duplicate/2 (tail recursion)
duplicate(X, Term) -> duplicate(X, Term, []). duplicate(0, _, List) -> List; duplicate(X, Term, List) when X > 0 -> duplicate(X-1, Term, [Term | List]).
reverse([]) -> []; reverse([H|T]) -> reverse(T)++[H].
reverse([1,2,3,4]) = [4]++[3]++[2]++[1] ↑ ↵ = [4,3]++[2]++[1] ↑ ↑ ↵ = [4,3,2]++[1] ↑ ↑ ↑ ↵ = [4,3,2,1].
The diagram from the book is confusing. But it took a bit and a hot shower and I understand it. Look at the code.
Remember this isn't tail recursion. It have to expand and it calculate after it reaches the base and start to pop off the stack. The diagram that the book gave is when already branch all the way down. It's showing us the stack popping where it have to slowly append each list item.
reverse([H|T]) -> reverse(T)++[H].
reverse([1,2,3,4]) = reverse([2,3,4])++[1] = reverse([3,4])++[2]++[1] = reverse([4])++[3]++[2]++[1] = [4]++[3]++[2]++[1] = [4,3]++[2]++[1] = [4,3,2]++[1] = [4,3,2,1]
reverse(List) -> reverse(List, Acc) reverse([],Acc) -> Acc; reverse([H|T],Acc) -> reverse(T,[Acc|H]).
tail_reverse([1,2,3,4]) = tail_reverse([2,3,4], [1]) = tail_reverse([3,4], [2,1]) = tail_reverse([4], [3,2,1]) = tail_reverse([], [4,3,2,1]) = [4,3,2,1]
...which takes a list L and an integer N, and returns the N first elements of the list.--book
where N=0 and L=[] (an empty list)
duplicate(0, []) -> []; duplicate(_,[]) -> [];
a function that calls itself
duplicate(N,[H | T]) when N > 0 -> [H | duplicate(N-1,T)].
Is this right? Not sure because I don't believe the base case of duplicate(0, []) -> []; would work. I'm thinking it's duplicate(0, L) -> L; Oh well time to check the book solution.
sublist(_,0) -> []; sublist([],_) -> []; sublist([H|T],N) when N > 0 -> [H|sublist(T,N-1)].
Ah, should be sublist(_,0) -> [];. My parameter order is different from the book and I forgot that the function is named sublist not duplicate.
Tail recursion my answer modifying the book non-tail recursion answer:
sublist/2 tail recursion (my answer)
sublist(L, N) -> sublist(L, N, []). sublist(_, 0, Acc) -> Acc; sublist([], _, Acc) -> Acc; sublist([H|T], N, Acc) when N > 0 -> sublist(T, N-1, [H | Acc]).
sublist/2 tail recursion (book's answer)
tail_sublist(L, N) -> tail_sublist(L, N, []). tail_sublist(_, 0, SubList) -> SubList; tail_sublist([], _, SubList) -> SubList; tail_sublist([H|T], N, SubList) when N > 0 -> tail_sublist(T, N-1, [H|SubList]).
If you compile this function as is, sublist([1,2,3,4,5,6],3) would not return [1,2,3], but [3,2,1].
tail_sublist(L, N) -> reverse(tail_sublist(L, N, [])).
tail_sublist(L, N) -> lists:reverse(tail_sublist(L, N, [])).
A zipping function will take two lists of same length as parameters and will join them as a list of tuples which all hold two terms.--book
1> recursive:zip([a,b,c],[1,2,3]). [{a,1},{b,2},{c,3}]
a function that calls itself
zip([H1 | T1],[H2 | T2]) -> [{H1, H2}, zip(T1, T2)];
zip([],[]) -> []; zip([X|Xs],[Y|Ys]) -> [{X,Y}|zip(Xs,Ys)].
My mistakes: . instead of ; and , instead of |
However, if you wanted a more lenient zip function, you could decide to have it finish whenever one of the two list is done.--book
lenient_zip([],_) -> []; lenient_zip(_,[]) -> []; lenient_zip([X|Xs],[Y|Ys]) -> [{X,Y}|lenient_zip(Xs,Ys)].