Skip to content

Instantly share code, notes, and snippets.

@shakerlxxv
Last active March 25, 2017 18:11
Show Gist options
  • Save shakerlxxv/426871b87859825d334cd9b19018d594 to your computer and use it in GitHub Desktop.
Save shakerlxxv/426871b87859825d334cd9b19018d594 to your computer and use it in GitHub Desktop.
%%==============================================================================
%% Univ. Kent Functional Programing with Erlang
%% Week 3: Part 11 - Functions as results in practice
%%
%% Description:
%% consolidate understanding of functions that take functions as
%% arguments and return functions as results.
%%
%% Author: Brian L. Shaver
%% Date : 2017-03-25
%%==============================================================================
-module(hof).
-include_lib("eunit/include/eunit.hrl").
-export([add/1,times/1,compose/2,id/1,iterate/1,f2ofg2/1,twice/1,composes/1]).
%-------------------------------------------------------------------------------
% example for same composition either order
f1() ->
fun _(X) -> X + 1 end.
g1() ->
fun _(Y) -> Y - 1 end.
f1ofg1(X) ->
(compose(f1(),g1()))(X).
g1off1(Y) ->
(compose(g1(),f1()))(Y).
compose1_test_() ->
[
?_assertEqual(f1ofg1(0),g1off1(0)),
?_assertEqual(f1ofg1(9),g1off1(9))
].
%-------------------------------------------------------------------------------
% example for different composition other order
f2() ->
fun _(X) -> X - 1 end.
g2() ->
fun _(X) -> X * 3 end.
f2ofg2(X) ->
(compose(f2(),g2()))(X).
g2off2(Y) ->
(compose(g2(),f2()))(Y).
compose2_test() ->
% only single counter example required to prove non-commutative
?assertNotEqual(f2ofg2(3),g2off2(3)).
%-------------------------------------------------------------------------------
% function which composes a list of functions
composes(L) ->
lists:foldr(fun compose/2,fun(Z) -> Z end, L).
composes_test_() ->
[
?_assertEqual(f2ofg2(3),(composes([f2(),g2()]))(3)),
?_assertEqual(f2ofg2(3 + 1),(composes([f1(),f2(),g2()]))(3)),
?_assertEqual(f2ofg2(4),(composes([g1(),f1(),f2(),g2()]))(4))
].
%-------------------------------------------------------------------------------
% apply a function to itself
twice(F) ->
compose(F,F).
twice_test() ->
?assertEqual(18,(twice(g2()))(2)).
%-------------------------------------------------------------------------------
% apply a function to a function applying a function to itself
twice_twice(F) ->
(compose(fun twice/1,fun twice/1))(F).
twice_twice_test() ->
?assertEqual(162,(twice_twice(g2()))(2)).
%-------------------------------------------------------------------------------
% iterate calling a function N times
iterate(0) ->
fun(X) -> X end;
iterate(N) when N > 0 ->
% this version is off by 1 in my opinion because its iterating
% one more time for the 0, so iterate(1) is calling the function twice
% which I find to be unintuitive.
% fun(F) -> compose(F,(iterate(N-1))(F)) end.
% credit Giancarlo Valente for the approach below
fun(F) -> composes(lists:duplicate(N,F)) end.
iterate_test_() ->
[
% iterate 1 +1 4 times
?_assertEqual(5,((iterate(4))(f1()))(1)),
% 4 * 3 * 3
?_assertEqual(36,((iterate(2))(g2()))(4))
].
%-------------------------------------------------------------------------------
% hof initial code
add(X) ->
fun(Y) -> X+Y end.
times(X) ->
fun(Y) ->
X*Y end.
compose(F,G) ->
fun(X) -> G(F(X)) end.
id(X) ->
X.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment