You can learn more about working with higher order functions in Chapter 9 of Erlang Programming, Section 3.4 of Programming Erlang, Section 2.7 of Erlang and OTP in Action, and Chapter 6 of Learn You Some Erlang For Great Good!. List comprehensions are in Chapter 9 of Erlang Programming, Section 3.6 of Programming Erlang, Section 2.9 of Erlang and OTP in Action, and Chapter 1 of Learn You Some Erlang For Great Good!.
In calculus, the derivative of a function is "a measure of how a function changes as its input changes" (Wikipedia). For example, if an object is traveling at a constant velocity, that velocity is the same from moment to moment, so the derviative is zero. If an object is falling, its velocity changes a little bit as the object starts falling, and then falls faster and faster as time goes by.
You can calculate the rate of change of a function by calculating:
(F(X + Delta)  F(X)) / Delta
, where Delta
is the interval
between measurements. As Delta approaches zero, you get closer and
closer to the true value of the derivative.
Write a module named calculus
with a function derivative/2
. The
first argument is the function whose derivative you wish to find, and the
second argument is the point at which you are measuring the derivative.
What should you use for a value of Delta
? I used 1.0e10
, as that is a small
number that approaches zero.
Here is some sample output.
1>
c
(
calculus
).
{ok,calculus}
2>
F1
=
fun
(
X
)
>
X
*
X
end
.
#Fun<erl_eval.6.82930912>
3>
F1
(
3
).
9
4>
calculus
:
derivative
(
F1
,
3
).
6.000000496442226
5>
calculus
:
derivative
(
fun
(
X
)
>
3
*
X
*
X
+
2
*
X
+
1
end
,
5
).
32.00000264769187
6>
calculus
:
derivative
(
fun
math
:
sin
/
1
,
0
).
1.0
F1
function works.
fun
followed by the module:function/arity
.
Is it possible to use pattern matching inside a list comprehension? Try it and find out.
Presume you have this list of people’s names, genders, and ages:
People = [{"Federico", $M, 22}, {"Kim", $F, 45}, {"Hansa", $F, 30}, {"Tran", $M, 47}, {"Cathy", $F, 32}, {"Elias", $M, 50}].
In erl
(or in a module, if you prefer), write a list comprehension
that creates a list consisting of the names of all males who are over 40.
Use pattern matching
to separate the tuple into three variables, and two guards to do the
tests for age and gender.
When you use multiple guards in a list comprehension, you get the moral
equivalent of and
for each condition you are testing. If you want an
or
condition, you must test it explicitly. Write a list comprehension
that selects the names of all the people who are male or over 40. You
will need one guard with an or
; you may also use orelse
.
Because or
has higher priority than comparison operators like <
and
==
, an expression like X > 5 or X < 12
will generate an error, as
Erlang interprets it to mean X > (5 or X) < 12
. Use parentheses to force
the correct evaluation: (X > 5) or (X < 12)
. If you use orelse
, which
has a lower priority than the comparison operators, you don’t need the
parentheses, though it doesn’t hurt to have them. Another advantage of
orelse
is that it doesn’t do any unnecessary comparisons.
lists:foldl/3
Add mean/1
and stdv/1
functions to the stats
module which
you created in Étude 62 to calculate the mean and
standard deviation for a list of numbers.
1>
c
(
stats
).
{ok,stats}
2>
stats
:
mean
([
7
,
2
,
9
]).
6.0
3>
stats
:
stdv
([
7
,
2
,
9
]).
3.605551275463989
The formula for the mean is simple; just add up all the numbers and
divide by the number of items in the list (which you may find by using the
length/1
function).Use lists:foldl/3
to calculate the sum of the items
in the list.
The following is the algorithm for calculating
the standard deviation. Presume that N
is the number of items
in the list.
N
times the sum of squares.
N * (N  1)
.
Thus, if your numbers are 7, 2, and 9, N
would be three, and
you would do these calculations:
N
times the sum of squares is 134 * 3, or 402.
In your code, you can do steps three through seven in one arithmetic expression. You’d have variables in your expression rather than constants, of course.
math:sqrt((3 * 134  18 * 18)/(3 * (3  1))
Use lists:foldl/3
to calculate the sum and the sum of squares.
Bonus points if you can calculate both of them
with one call to lists:foldl/3
. Hint:
the argument for the accumulator doesn’t have to be a single number. It can
be a list or a tuple.
lists:split/2
Use erl man lists
to see how the lists:split/2
function works, or try
the following example and see if you can figure it out. Experiment to see
what happens if the first argument is zero.
1>
lists
:
split
(
4
,
[
110
,
220
,
330
,
440
,
550
,
660
]).
{[110,220,330,440],[550,660]}
Use lists:split/2
and lists:foldl/3
to rewrite the
dates:julian/1
function from
Étude 63. Hint: you’ll use those functions when
calculating the total number of days up to (but not including)
the month in question.
Back to list comprehensions. You can have more than one generator in a list
comprehension. Try this in erl
:
1>
[
X
*
Y

X
<
[
3
,
5
,
7
],
Y
<
[
2
,
4
,
6
]].
[6,12,18,10,20,30,14,28,42]
Using what you’ve learned from this example, write a module named cards
that contains a function make_deck/0
. The function will generate a deck
of cards as a list 52 tuples in this form:
[{"A","Clubs"}, {"A","Diamonds"}, {"A","Hearts"}, {"A","Spades"}, {2,"Clubs"}, {2,"Diamonds"}, {2,"Hearts"}, {2,"Spades"}, ... {"K", "Clubs"}, {"K", "Diamonds"}, {"K", "Hearts"}, {"K", "Spades"}]
When you run this function, your output will not show the entire list; it will show something that ends like this. Don’t freak out.
{7,"Clubs"}, {7,"Diamonds"}, {7,[...]}, {7,...}, {...}...]
If you want to see the full list, use this function.
show_deck(Deck) >
lists:foreach(fun(Item) > io:format("~p~n", [Item]) end, Deck).
You need a way to shuffle the deck of cards. This is the code for doing a shuffle, taken from the Literate Programs Wiki.
shuffle
(
List
)
>
shuffle
(
List
,
[]).
shuffle
([],
Acc
)
>
Acc
;
shuffle
(
List
,
Acc
)
>
{
Leading
,
[
H

T
]}
=
lists
:
split
(
random
:
uniform
(
length
(
List
))

1
,
List
),
shuffle
(
Leading
++
T
,
[
H

Acc
]).
Wait a moment. If I’ve just given you the code, what’s the purpose
of this étude? I want you to understand the code. The object of this
étude is to write the documentation for the algorithm.
If you aren’t sure what the code does, try adding some
io:format
statements to see what is happening. If you’re totally
stuck, see the explanation from Literate Programs site.