Skip to content

Instantly share code, notes, and snippets.

@huseyinyilmaz
Last active August 29, 2015 14:21
Show Gist options
  • Save huseyinyilmaz/fe1c3be4f8fd69628a6d to your computer and use it in GitHub Desktop.
Save huseyinyilmaz/fe1c3be4f8fd69628a6d to your computer and use it in GitHub Desktop.
Functional_programming_with_erlang week 3
-module(funs).
-export([compose/1]).
-export([twice/1]).
-export([iteration/1]).
-export([make_list/2]).
-include_lib("eunit/include/eunit.hrl").
compose(Funs)->
fun(Arg) ->
lists:foldl(
fun(Fun,Result) -> Fun(Result) end,
Arg,
Funs)
end.
twice(Fun) -> compose([Fun,Fun]).
% takes an Item and a number N and returns a list
% that contains that Item N times.
make_list(0, _) -> [];
make_list(N, Item) when N>0 -> [Item|make_list(N-1, Item)].
% repeates given function n times.
iteration(N) ->
fun(Fun) -> compose(make_list(N, Fun)) end.
%%%%%%%%%%%
%% TESTS %%
%%%%%%%%%%%
test_double(X) -> X * 2.
test_increment(X) -> X + 1.
compose_1_test() -> ?assertEqual(5, (compose([fun test_double/1, fun test_increment/1]))(2)).
compose_2_test() -> ?assertEqual(6, (compose([fun test_increment/1, fun test_double/1]))(2)).
twice_1_test() -> ?assertEqual(8, (twice(fun test_double/1))(2)).
twice_2_test() -> ?assertEqual(4, (twice(fun test_increment/1))(2)).
twice_3_test() -> ?assertEqual(32, ((twice(fun twice/1))(fun test_double/1))(2)).
twice_4_test() -> ?assertEqual(6, ((twice(fun twice/1))(fun test_increment/1))(2)).
iteration_1_test() -> ?assertEqual(5, ((iteration(0))(fun test_increment/1))(5)).
iteration_2_test() -> ?assertEqual(10, ((iteration(5))(fun test_increment/1))(5)).
-module(one_five).
-export([doubleAll/1]).
-export([evens/1]).
-export([product/1]).
-export([zip/2]).
-export([zip_with/3]).
-export([zip_with2/3]).
-include_lib("eunit/include/eunit.hrl").
-spec doubleAll([integer()]) -> [integer()].
doubleAll(Xs) -> lists:map(fun(X)-> X*2 end,Xs).
-spec evens([integer()]) -> [integer()].
evens(Xs) -> lists:filter(fun(X)->(X rem 2) == 0 end, Xs).
-spec product([integer()]) -> integer().
product(Xs) -> lists:foldr(fun(X, Acc) -> Acc*X end,1,Xs).
-spec zip_with(_,[any()],[any()]) -> [any()].
zip_with(_, [], _) -> [];
zip_with(_, _, []) -> [];
zip_with(F, [X|Xs], [Y|Ys]) -> [F(X,Y)|zip_with(F,Xs,Ys)].
-spec zip_with2(_,[any()],[any()]) -> [any()].
zip_with2(F, Xs, Ys) -> lists:map(fun({X,Y})->F(X,Y)end,zip(Xs,Ys)).
-spec zip([T], [V]) -> [{T,V}].
zip(Xs, Ys) -> zip_with(fun(X,Y)-> {X,Y} end, Xs, Ys).
%%%%%%%%%%%
%% TESTS %%
%%%%%%%%%%%
double_all_1_test() -> ?assertEqual([], doubleAll([])).
double_all_2_test() -> ?assertEqual([0,2,4,6], doubleAll([0,1,2,3])).
evens_1_test() -> ?assertEqual([], evens([])).
evens_2_test() -> ?assertEqual([2,4], evens([1,2,3,4])).
product_1_test() -> ?assertEqual(1, product([])).
product_2_test() -> ?assertEqual(24, product([1,2,3,4])).
zip_with_1_test() -> ?assertEqual([],zip_with(fun(X,Y) -> X+Y end, [1,3], [])).
zip_with_2_test() -> ?assertEqual([ 3, 7 ],
zip_with(fun(X,Y) -> X+Y end, [1,3,5,7], [2,4])).
zip_with2_1_test() -> ?assertEqual([],zip_with2(fun(X,Y) -> X+Y end, [1,3], [])).
zip_with2_2_test() -> ?assertEqual([ 3, 7 ],
zip_with2(fun(X,Y) -> X+Y end, [1,3,5,7], [2,4])).
-module(rock_paper_scissors).
-export([beat/1]).
-export([lose/1]).
-export([result/2]).
-include_lib("eunit/include/eunit.hrl").
beat(rock) -> paper;
beat(paper) -> scissors;
beat(scissors) -> rock.
lose(rock) -> scissors;
lose(scissors) -> paper;
lose(paper) -> rock.
% return 1 for win
% 0 for draw
% -1 for loose
result(First, Second) ->
case {beat(First),lose(First)} of
{Second,_} -> -1;
{_, Second} -> 1;
{_, _} -> 0
end.
tournament(Xs, Ys) -> lists:foldr(fun({L,R},Sum)-> Sum + result(L,R) end,
0, lists:zip(Xs,Ys)).
%%%%%%%%%%%
%% TESTS %%
%%%%%%%%%%%
beat_1_test() -> ?assertEqual(paper, beat(rock)).
lose_1_test() -> ?assertEqual(scissors, lose(rock)).
result_1_test() -> ?assertEqual(0, result(rock,rock)).
result_2_test() -> ?assertEqual(0, result(paper,paper)).
result_3_test() -> ?assertEqual(0, result(scissors,scissors)).
result_4_test() -> ?assertEqual(-1, result(rock,paper)).
result_5_test() -> ?assertEqual(-1, result(paper,scissors)).
result_6_test() -> ?assertEqual(-1, result(scissors,rock)).
result_7_test() -> ?assertEqual(1, result(paper, rock)).
result_8_test() -> ?assertEqual(1, result(scissors, paper)).
result_9_test() -> ?assertEqual(1, result(rock, scissors)).
tournament_1_test() -> ?assertEqual(0, tournament([], [])).
tournament_2_test() -> ?assertEqual(-1, tournament([rock,rock,paper,paper],
[rock,paper,scissors,rock])).
tournament_3_test() -> ?assertEqual(-3, tournament([rock,rock,rock],
[paper,paper,paper])).
-module(rps).
-export([play/1,echo/1,play_two/3,rock/1,no_repeat/1,const/1,enum/1,cycle/1,rand/1,val/1,tournament/2]).
-include_lib("eunit/include/eunit.hrl").
%% Source:
%% http://erlang.org/doc/reference_manual/typespec.html
-type choice()::rock|paper|scissors.
-type strategy()::fun(([choice()])->choice()).
-type result()::win|lose|result.
%
% play one strategy against another, for N moves.
%
-spec play_two(strategy(), strategy(), integer())-> integer().
play_two(StrategyL,StrategyR,N) ->
play_two(StrategyL,StrategyR,[],[],N).
% tail recursive loop for play_two/3
% 0 case computes the result of the tournament
% FOR YOU TO DEFINE
% REPLACE THE dummy DEFINITIONS
-spec play_two(strategy(),strategy(),[choice()],[choice()],integer())->integer().
play_two(_,_,PlaysL,PlaysR,0) ->
Result = tournament(PlaysL, PlaysR),
io:format("Finished Left Player = ~p , Right Player = ~p~n Result is ~p~n", [PlaysL, PlaysR, Result]),
Result;
play_two(StrategyL,StrategyR,PlaysL,PlaysR,N) ->
{PlayL,PlayR} = {StrategyL(PlaysR), StrategyR(PlaysL)},
play_two(StrategyL, StrategyR, [PlayL|PlaysL],[PlayR|PlaysR], N-1).
%
% interactively play against a strategy, provided as argument.
%
-spec play(strategy())-> ok.
play(Strategy) ->
io:format("Rock - paper - scissors~n"),
io:format("Play one of rock, paper, scissors, ...~n"),
io:format("... r, p, s, stop, followed by '.'~n"),
play(Strategy,[]).
% tail recursive loop for play/1
-spec play(strategy(), [choice()])-> ok.
play(Strategy,Moves) ->
{ok,P} = io:read("Play: "),
Play = expand(P),
case Play of
stop ->
io:format("Stopped~n");
_ ->
Result = result(Play,Strategy(Moves)),
io:format("Result: ~p~n",[Result]),
play(Strategy,[Play|Moves])
end.
%
% auxiliary functions
%
% transform shorthand atoms to expanded form
-spec expand(atom()) -> atom().
expand(r) -> rock;
expand(p) -> paper;
expand(s) -> scissors;
expand(X) -> X.
% result of one set of plays
-spec result(choice(), choice())->result().
result(rock,rock) -> draw;
result(rock,paper) -> lose;
result(rock,scissors) -> win;
result(paper,rock) -> win;
result(paper,paper) -> draw;
result(paper,scissors) -> lose;
result(scissors,rock) -> lose;
result(scissors,paper) -> win;
result(scissors,scissors) -> draw.
% result of a tournament
-spec tournament([choice()], [choice()]) -> integer().
tournament(PlaysL,PlaysR) ->
lists:sum(
lists:map(fun outcome/1,
lists:zipwith(fun result/2,PlaysL,PlaysR))).
-spec outcome(result()) -> integer().
outcome(win) -> 1;
outcome(lose) -> -1;
outcome(draw) -> 0.
% transform 0, 1, 2 to rock, paper, scissors and vice versa.
-spec enum(integer()) -> choice().
enum(0) ->
rock;
enum(1) ->
paper;
enum(2) ->
scissors.
-spec val(choice()) -> integer().
val(rock) ->
0;
val(paper) ->
1;
val(scissors) ->
2.
% give the play which the argument beats.
-spec beats(choice()) -> choice().
beats(rock) ->
scissors;
beats(paper) ->
rock;
beats(scissors) ->
paper.
%
% strategies.
%
-spec echo([choice()])->choice().
echo([]) ->
paper;
echo([Last|_]) ->
Last.
-spec rock([choice()])->choice().
rock(_) ->
rock.
% FOR YOU TO DEFINE
% REPLACE THE dummy DEFINITIONS
-spec no_repeat([choice()])->choice().
no_repeat([]) ->
paper;
no_repeat([X|_]) ->
X.
% Constant?
-spec const([choice()])->choice().
const(_Play) ->
paper.
-spec cycle([choice()])->choice().
cycle(Xs) ->
enum(erlang:length(Xs) rem 3).
-spec rand([choice()])->choice().
rand(_) ->
enum(random:uniform(3)-1).
%%%%%%%%%%
%% TEST %%
%%%%%%%%%%
beats_test() -> ?assertEqual(rock, beats(paper)).
play_two_1_test() -> ?assertEqual(0, play_two(fun rock/1, fun rock/1,[],[],5)).
play_two_2_test() -> ?assertEqual(-1, play_two(fun rock/1, fun echo/1,[],[],5)).
play_two_3_test() -> ?assertEqual(1, play_two(fun echo/1, fun rock/1,[],[],5)).
play_two_4_test() -> ?assertEqual(-1, play_two(fun cycle/1, fun const/1,[],[],5)).
play_two_5_test() -> ?assertEqual(3, play_two(fun cycle/1, fun no_repeat/1,[],[],5)).
%% how to call dialyzer
%% 1) build plt
%% dialyzer --build_plt --apps erts kernel stdlib crypto mnesia sasl eunit
%% 2) call dialyzer rps.erl
%% Output:
%% Huseyins-MacBook-Air:week_3 huseyin$ dialyzer rps.erl
%% Checking whether the PLT /Users/huseyin/.dialyzer_plt is up-to-date... yes
%% Proceeding with analysis...
%% rps.erl:116: The pattern 'rock' can never match the type 'paper'
%% rps.erl:120: The pattern 'scissors' can never match the type 'paper'
%% done in 0m0.71s
%% done (warnings were emitted)
%% Huseyins-MacBook-Air:week_3 huseyin$
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment