Last active
December 18, 2015 03:19
-
-
Save granolocks/5717375 to your computer and use it in GitHub Desktop.
Most of the functions in this module are inspired by the guides in this site: http://learnyousomeerlang.com/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -module(recursive_functions). | |
| -export([ | |
| factorial/1, | |
| tail_fac/1, | |
| tail_fac/2, | |
| recursive_length/1, | |
| tail_len/1, | |
| tail_len/2, | |
| duplicate/2, | |
| tail_duplicate/2, | |
| tail_duplicate/3, | |
| reverse/1, | |
| tail_reverse/1, | |
| tail_reverse/2 | |
| ]). | |
| -author("Gabe Koss"). | |
| %% oh look! Recursion to calculate factorials as in: | |
| %% | |
| %% 4! = 4 x 3! | |
| %% 4! = 4 x 3 x 2! | |
| %% 4! = 4 x 3 x 2 x 1! | |
| %% 4! = 4 x 3 x 2 x 1 x 1 | |
| %% | |
| %% Pattern match on 0 to return 1 | |
| factorial(0) -> 1; | |
| %% otherwise recursively calculate down til N = 0 | |
| factorial(N) when N > 0 -> N*factorial(N-1). | |
| %% This is a bit of a memory hog, so alternatively we can use what is called "tail recursion" | |
| %% This is similar to a ruby inject | |
| %% | |
| %% tail_fac(4) = tail_fac(4,1) | |
| %% tail_fac(4,1) = tail_fac(4-1, 4*1) | |
| %% tail_fac(3,4) = tail_fac(3-1, 3*4) | |
| %% tail_fac(2,12) = tail_fac(2-1, 2*12) | |
| %% tail_fac(1,24) = tail_fac(1-1, 1*24) | |
| %% tail_fac(0,24) = 24 | |
| %% | |
| %% Note: this requires two exported functions since the arity is not the same | |
| tail_fac(N) -> tail_fac(N,1). | |
| tail_fac(0,Acc) -> Acc; | |
| tail_fac(N,Acc) when N > 0 -> tail_fac(N-1, N*Acc). | |
| %% Here is another recursive function to calculate the length of a list... | |
| %% O_o this is mind boggling | |
| %% from http://learnyousomeerlang.com/recursion | |
| %% len([1,2,3,4]) = len([1 | [2,3,4]) | |
| %% = 1 + len([2 | [3,4]]) | |
| %% = 1 + 1 + len([3 | [4]]) | |
| %% = 1 + 1 + 1 + len([4 | []]) | |
| %% = 1 + 1 + 1 + 1 + len([]) | |
| %% = 1 + 1 + 1 + 1 + 0 | |
| %% = 1 + 1 + 1 + 1 | |
| %% = 1 + 1 + 2 | |
| %% = 1 + 3 | |
| %% = 4 | |
| %% establish base case | |
| recursive_length([]) -> 0; | |
| %% recursivel work towards base case | |
| recursive_length([_|T]) -> 1 + recursive_length(T). | |
| %% | |
| %% and to use Tail recursiion | |
| tail_len(N) -> tail_len(N,0). | |
| tail_len([],Acc) -> Acc; | |
| tail_len([_|T], Acc) -> tail_len(T, Acc+1). | |
| %% Another one, this takes a Number and a Term and then returns a list with | |
| %% a number of elements equal to the seeded number, entirely consisting of the Term | |
| duplicate(0,_) -> | |
| []; | |
| duplicate(N,Term) when N > 0 -> | |
| [Term|duplicate(N-1,Term)]. | |
| %% and using the tail recursion logic | |
| %% | |
| %% tail_duplicate(4,foo) = tail_duplicate(4, foo, []) | |
| %% = tail_duplicate(3, foo, [foo]) | |
| %% = tail_duplicate(2, foo, [foo, foo]) | |
| %% = tail_duplicate(1, foo, [foo, foo, foo]) | |
| %% = tail_duplicate(0, foo, [foo, foo, foo, foo]) | |
| %% = [foo, foo, foo, foo] | |
| %% | |
| tail_duplicate(N,Term) -> | |
| tail_duplicate(N,Term,[]). | |
| %% This flavor has an arity of 3, allowing it to include a | |
| %% collector list | |
| %% | |
| %% When N is reduced to 0, disregard Term | |
| %% and return the List | |
| tail_duplicate(0,_,List) -> | |
| List; | |
| tail_duplicate(N,Term,List) -> | |
| %% decrement N, add Term as new head of List, | |
| tail_duplicate(N-1,Term,[Term|List]). | |
| %% recursively reverse a list | |
| %% reverse([1,2,3,4]) = [4]++[3]++[2]++[1] | |
| %% ↑ ↵ | |
| %% = [4,3]++[2]++[1] | |
| %% ↑ ↑ ↵ | |
| %% = [4,3,2]++[1] | |
| %% ↑ ↑ ↑ ↵ | |
| %% = [4,3,2,1] | |
| reverse([]) -> []; | |
| reverse([H|T]) -> reverse(T) ++ [H]. | |
| %% with tail recursion | |
| %% | |
| %% tail_reverse([1,2,3]) = tail_reverse([1,2,3],[]) | |
| %% = tail_reverse([2,3], [1]) | |
| %% = tail_reverse([3], [2,1]) | |
| %% = tail_reverse([], [3,2,1]) | |
| %% = [3,2,1] | |
| tail_reverse(List) -> | |
| tail_reverse(List,[]). | |
| tail_reverse([], Acc) -> | |
| Acc; | |
| tail_reverse([H|T], Acc) -> | |
| tail_reverse(T, [H|Acc]). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| %% Most of the functions in this module are inspired by the guides in | |
| %% this site: http://learnyousomeerlang.com/ | |
| %% | |
| %% Hyphen prefixed declarations are headers used at compile time. | |
| %% | |
| %% Module Declaration | |
| -module(sample_module). | |
| %% | |
| %% List of exportable functions | |
| %% FORMAT: function_name/<arity> | |
| %% | |
| -export([ | |
| calculate_age/1, | |
| head/1, | |
| second/1, | |
| same_value/2, | |
| valid_time/1, | |
| say_hello/2, | |
| say_age/1, | |
| say_age_with_if/1, | |
| say_age_with_case_of/1, | |
| case_age_string/1, | |
| greet_and_calculate_age/3, | |
| factorial/1, | |
| recursive_length/1 | |
| ]). | |
| -author("Gabe Koss"). | |
| %% | |
| %% Define a static value or a macro. | |
| %% obviously the Current Year may not be the best thing to set ;) | |
| %% this is just for the syntax example and a study reminder | |
| %% | |
| -define(CURRENT_YEAR,2013). | |
| %% notice how the pattern matching | |
| %% is used to extract info from the list | |
| head([Head|_]) -> | |
| Head. | |
| second([_,Second|_]) -> | |
| Second. | |
| %% another example of this for pattern matching | |
| %% as a way to defining the function behavior | |
| same_value(X,X) -> | |
| true; | |
| same_value(_,_) -> | |
| false. | |
| %% Another example of this... god this is cool | |
| %% It is easy to see how this will become useful for | |
| %% json validation and other types of parsing | |
| %% | |
| %% In the first example we take 1 tuple as an argument | |
| %% that contains two named tuples of three Named values | |
| %% | |
| %% Note: This has an arity of 1 | |
| valid_time({ | |
| Date = {Y,M,D}, | |
| Time = {H,Min,S} | |
| }) -> | |
| io:format("The Date tuple (~p) says today is: ~p/~p/~p,~n",[Date,Y,M,D]), | |
| io:format("The Time tuple (~p) indicates: ~p:~p:~p.~n", [Time,H,Min,S]); | |
| %% In the second version, anythin gthat doesn't match the expected format | |
| %% raises an error | |
| valid_time(_) -> | |
| io:format("Stop feeding me wrong data!~n"). | |
| %% basic print hello world function | |
| %% | |
| %% NOTE: how the behavior of the function is defined by | |
| %% by the arguments definition | |
| %% | |
| %% Ruby equivalent: | |
| %% | |
| %% def hello(gender, name) | |
| %% if gender == :male | |
| %% puts "Hello, Mr. #{name}!\n" | |
| %% elsif gender == :female | |
| %% puts "Hello, Mr. #{name}!\n" | |
| %% else | |
| %% puts "Hello, #{name}!\n" | |
| %% end | |
| %% end | |
| say_hello(male, Name) -> | |
| io:format("Hello, Mr. ~s!~n",[Name]); | |
| say_hello(female, Name) -> | |
| io:format("Hello, Ms. ~s!~n",[Name]); | |
| say_hello(_, Name) -> | |
| io:format("Hello, ~s!~n",[Name]). | |
| %% Subtract the year two values | |
| calculate_age(YearOfBirth) -> | |
| ?CURRENT_YEAR - YearOfBirth. | |
| %% The when clause after the function declaration is called a "Guard" | |
| %% which serves to validate the format of arguments | |
| say_age(Age) when Age > 0, Age =< 130 -> | |
| io:format("You are, ~s!~n",[Age]); | |
| say_age(Age) when Age =< 0 -> | |
| io:format("You are... a negative number of years old... Are you Merlin?!~n"); | |
| say_age(_) -> | |
| io:format("You are far too old!~n"). | |
| %% An alternative approach for this would be a more traditional | |
| %% if statement. This is less than ideal for Erlang, but | |
| %% is being added here for the purpose of of an example. | |
| %% | |
| %% See the what_the_if module at http://learnyousomeerlang.com/syntax-in-functions for more info about | |
| %% why this is a bad idea | |
| say_age_with_if(Age) -> | |
| String = if Age =< 0 -> "You are... a negative number of years old... Are you Merlin?!"; | |
| Age >= 130 -> "You are far too old!"; | |
| %% This interpolation style makes me sad, MUST be a better way to do this | |
| %% from: ttp://stackoverflow.com/questions/588003/convert-an-integer-to-a-string-in-erlang | |
| true -> lists:flatten(io_lib:format("You are ~p!", [Age])) | |
| end, | |
| io:format(String ++ "~n"). | |
| %% One final variant on this same theme would be a case ... of statement | |
| case_age_string(Age) -> | |
| case Age of | |
| N when N > 0, N =< 130 -> | |
| %% for fun an tlernate interpolation trick | |
| "You are " ++ erlang:integer_to_list(N) ++ "!"; | |
| N when N =< 0 -> | |
| "You are... a negative number of years old... Are you Merlin?!"; | |
| _ -> "You are far too old!" | |
| end. | |
| say_age_with_case_of(Age) -> | |
| io:format(case_age_string(Age) ++ "~n"). | |
| greet_and_calculate_age(Gender, Name, YearOfBirth) -> | |
| say_hello(Gender, Name), | |
| say_age(calculate_age(YearOfBirth)). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment