Tag Archives: Erlang

Erlang Thursday – queue:peek/1

For today’s Erlang Thursday we continue looking at the queue module and look at queue:peek/1 from the Extended API.

queue:peek/1 takes a queue as it’s argument and returns either the atom empty if the queue is empty, or {value, Item} where Item is the item at the head of the queue.

QueueOne = queue:from_list([1, 2, 3, 4, 5]).
% {[5,4],[1,2,3]}
queue:peek(QueueOne).
% {value,1}
QueueOne.
% {[5,4],[1,2,3]}
EmptyQueue = queue:new().
% {[],[]}
queue:peek(EmptyQueue).
% empty

queue:peek/1 does not modify the existing queue at all either, so we can call it once as seen above, or multiple times as below, and the queue we peeked at doesn’t change.

QueueTwo = queue:from_list([a, b, c, d, e, f]).
% {[f,e],[a,b,c,d]}
queue:peek(QueueTwo).
% {value,a}
queue:peek(QueueTwo).
% {value,a}
queue:peek(QueueTwo).
% {value,a}
QueueTwo.
% {[f,e],[a,b,c,d]}

And unlike we saw in the previous Erlang Thursday on queue:head/1, we can safely peek at an empty queue instead of getting an exception.

queue:head(EmptyQueue).
% ** exception error: empty
%      in function  queue:head/1
%         called as queue:head({[],[]})
queue:peek(EmptyQueue).
% empty

Erlang’s queue module also contains queue:peek_r/1 which will peek at the element at the rear of the queue.

queue:peek_r(EmptyQueue).
% empty
queue:peek_r(QueueOne).
% {value,5}
queue:peek_r(QueueOne).
% {value,5}
queue:peek_r(QueueOne).
% {value,5}
queue:peek_r(QueueTwo).
% {value,f}
QueueTwo.
% {[f,e],[a,b,c,d]}
QueueOne.
% {[5,4],[1,2,3]}
EmptyQueue.
% {[],[]}

–Proctor

Erlang Thursday – queue:tail/1

In today’s Erlang Thursday we continue with the queue module’s Okasaki API, and look at queue:tail/1.

queue:tail/1 takes a non-empty queue as its argument, and returns a new queue with the first element removed.

Queue = queue:from_list([1, 2, 3, 4, 5]).
% {[5,4],[1,2,3]}
Tail = queue:tail(Queue).
% {[5,4],[2,3]}
Queue.
% {[5,4],[1,2,3]}
queue:head(Tail).
% 2
queue:to_list(Tail).
% [2,3,4,5]

We can see above that calling queue:tail/1 is not a destructive operation as might happen in other languages, and does indeed leave the original queue intact.

As part of the Okasaki API, which treats a queue as a double ended, queue:tail/1 has a counterpart function queue:liat/1 which will return a new queue with last item removed. queue:liat/1 also has an alias in the Okasaki API of queue:init/1.

queue:liat(Queue).
% {[4],[1,2,3]}
queue:init(Queue).
% {[4],[1,2,3]}
Queue.
% {[5,4],[1,2,3]}

Note that the Erlang documentation also shows that there is an alias queue:lait/1 which it points out should not be used because it is a misspelling.

And because we want to try to break things and see what we can learn, let’s try to call the different tail functions we have covered so far with an empty queue to see what happens.

EmptyQueue = queue:new().
% {[],[]}
queue:tail(EmptyQueue).
% ** exception error: empty
%      in function  queue:drop/1
%         called as queue:drop({[],[]})
queue:liat(EmptyQueue).
% ** exception error: empty
%      in function  queue:drop_r/1
%         called as queue:drop_r({[],[]})
queue:init(EmptyQueue).
% ** exception error: empty
%      in function  queue:drop_r/1
%         called as queue:drop_r({[],[]})

Looks like we get exception errors in queue:drop/1 and queue:drop_r/1 when we call queue:tail/1 and queue:liat/1 respectively.

And when we look at the behavior of queue:drop/1 and queue:drop_r/1 with a queue with items in it, it looks like queue:tail/1 is just an alias for queue:drop/1, and queue:liat/1 and queue:init/1 are just aliases for queue:drop_r/1.

queue:drop(Queue).
% {[5,4],[2,3]}
queue:drop_r(Queue).
{[4],[1,2,3]}

–Proctor

Erlang Thursday – queue:head/1

Today’s Erlang Thursday continues to dig into the Okasaki API of Erlang’s queue module, and take a look at queue:head/1.

queue:head/1 takes a queue as it’s first argument, and returns the first item in the queue.

Queue = queue:from_list([1, 2, 3, 4, 5]).
% {[5,4],[1,2,3]}
queue:head(Queue).
% 1
Queue.
% {[5,4],[1,2,3]}

As we can see in the example above, queue:head/1 function does not modify the original queue at all, but just returns the first item.

Because queue:head/1 only returns the value found at the head of the queue, and not a tagged tuple, it raises an error if we try to get the head item from an empty queue.

EmptyQueue = queue:new().
% {[],[]}
queue:head(EmptyQueue).
%** exception error: empty
%     in function  queue:head/1
%        called as queue:head({[],[]})

To be safe, and not get the error raised on an empty queue, the queue module also defines a function queue:is_empty/1 that you can use to check if a queue is empty.

queue:is_empty(EmptyQueue).
% true

Like queue:cons/2, and other functions of the Okasaki API, there is also a function queue:daeh (head backwards), to get the last item from the queue, as well as an alias for queue:daeh/1 of queue:last/1.

queue:daeh(Queue).
% 5
queue:last(Queue).
% 5

Both queue:daeh/1 and queue:last/1 also raise an error of empty if you call them with an empty queue as the argument.

queue:daeh(EmptyQueue).
% ** exception error: empty
%      in function  queue:get_r/1
%         called as queue:get_r({[],[]})
queue:last(EmptyQueue).
% ** exception error: empty
%      in function  queue:get_r/1
%         called as queue:get_r({[],[]})

And if we look at the error that is raised on queue:daeh/1 and queue:last/1, we see that the error is coming from queue:get_r/1 from the Extended API. If we look at the behavior of queue:get_r/1 it looks like queue:tail/1 and queue:daeh/1 are indeed just aliases for queue:get_r/1.

queue:get_r(Queue).
% 5
queue:get_r(EmptyQueue).
% ** exception error: empty
%      in function  queue:get_r/1
%         called as queue:get_r({[],[]})
queue:get_r(Queue).
% 5
Queue.
% {[5,4],[1,2,3]}

–Proctor

Erlang Thursday – queue:cons/2

Today’s Erlang Thursday digs a little into the queue module, and we cover queue:cons/2 from the Okasaki API.

queue:cons/2 takes a item and a queue, and will return a new queue with the item at the head of the queue.

queue:cons(7, queue:new()).
% {[],[7]}
queue:cons(3, queue:cons(7, queue:new())).
% {[7],[3]}
queue:cons(nil, queue:new()).
% {[],[nil]}
queue:cons(5, queue:from_list([7, 9, 13, 21])).
% {[21],[5,7,9,13]}

If we try to pass a list in to queue:cons/2, we see that it does want a queue, and will not do an implicit conversion of a list to a queue.

queue:cons(5, [1, 2, 3, 4]).
% ** exception error: bad argument
%      in function  queue:in_r/2
%         called as queue:in_r(5,[1,2,3,4])

As the queue is setup to be a double ended queue, the Okasaki API also provides a counter function queue:snoc/2, that adds an item to the tail of the queue passed in. Note that the argument order is swapped between queue:snoc/2 and queue:cons/2; queue:snoc/2 takes the queue as the first argument, and the item to add at the tail as the second argument.

queue:snoc(queue:new(), 5).
% {[5],[]}
queue:snoc(queue:from_list([7]), 5).
% {[5],[7]}
queue:snoc(queue:snoc(queue:new(), 7), 5).
% {[5],[7]}
queue:snoc(queue:from_list([7, 9, 13, 21]), 5).
% {[5,21],[7,9,13]}

–Proctor

Giving an Intro to Erlang workshop at LambdaConf 2015

Just a quick post letting anyone who is going to be at LambdaConf 2015 this weekend in Boulder, Colorado.

I will be there giving an Intro to Erlang workshop on this coming Friday, the 22nd of May, so if you are going make sure to look for me around there at least. 😀

Feel free to track me down and say hi, as I would love to meet you as well. The offer is open for you to chat me up about Erlang specifically, functional programming in general, or what ever else we might find interesting.

And if you are going and we meet up, I might just have some Functional Geekery stickers to give away.

Look forward to seeing you there.

–Proctor

Erlang Thursday – filelib:is_file/1

Today’s Erlang Thursday is filelib:is_file/1.

filelib:is_file/1 takes a string representing a filename, and returns a true or false depending on if the name refers to a file or directory.

This can be useful if you are having to read from a configuration file and need to ensure that the file or directory exists before trying to process it, so that you can give a nice error message before quitting, instead of just causing a system error to be raised.

filelib:is_file("foo").
% false
filelib:is_file("junk").
% true
filelib:is_file("tmp").
% true
filelib:is_file("tempmp").
% false
filelib:is_file("temp").
% true
filelib:is_file("/usr/local/bin").
% true
filelib:is_file("/usr/local/var").
% true
filelib:is_file("/usr/local/vars").
% false
filelib:is_file(".").
% true
filelib:is_file("..").
% true

filelib:is_file/1 can also take a atom, or even a deeplist(), representing the filename as well.

filelib:is_file(foo).
% false
filelib:is_file(junk).
% true
filelib:is_file(["/usr", ['/local', '/bin']]).
% true

–Proctor

Erlang Thursday – calendar:iso_week_number/1

Today’s Erlang Thursday is on calendar:iso_week_number/1.

calendar:iso_week_number/1 takes a date tuple as an argument, and returns a tuple of the year and week number. The year is the year passed as the date tuple, and the week number is an integer between 1 and 53.

calendar:iso_week_number({2015, 05, 04}).
{2015,19}
calendar:iso_week_number({2015, 05, 03}).
{2015,18}

If we use this week as an example, we can see that a week starts on Monday (the 4th of May), where the Sunday before (May 3rd) was the previous week.

We see that January 1st falls on the first week of the year, no surprise there, and that the 31st of December for 2015, is on the 53rd week of the year.

calendar:iso_week_number({2015, 1, 1}).
{2015,1}
calendar:iso_week_number({2015, 12, 31}).
{2015,53}

Having a 53rd week of the year sounds surprising at first, because everyone talks about 52 weeks in a year, until you realize that sometimes December 31st sometimes falls at the very beginning of a week, causing it to be the 53rd week, since it is only a partial week.

–Proctor

Erlang Thursday – calendar:is_leap_year/1

Today’s Erlang Thursday is on calendar:is_leap_year/1.

calendar:is_leap_year/1 takes a non-negative integer value representing a year, and will return true if that year is a leap year, or false otherwise.

calendar:is_leap_year(2015).
% false
calendar:is_leap_year(2012).
% true
calendar:is_leap_year(2017).
% false
calendar:is_leap_year(2000).
% true
calendar:is_leap_year(1900).
% false
calendar:is_leap_year(0).
% true

By having a built in function as part of the core Erlang libraries, it means you don’t have to code up the rules, or even go lookup the rules to remember how the century years are determined to be leap years or not.

And if you do pass in a negative number for the year, Erlang will raise an exception, as there are no clauses which match a negative number for the year.

calendar:is_leap_year(-1).
% ** exception error: no function clause matching calendar:is_leap_year(-1) (calendar.erl, line 183)
calendar:is_leap_year(-4).
% ** exception error: no function clause matching calendar:is_leap_year(-4) (calendar.erl, line 183)

–Proctor

Erlang Thursday – calendar:valid_date/3

Today’s Erlang Thursday is calendar:valid_date/3.

Originally, I was thinking it was going to be calendar:time_difference/3, but then I looked into the Erlang documentation for the calendar module. and saw that it was marked as obsolete, so today I present calendar:valid_date/3.

The arguments to calendar:valid_date/3 are an integer for the year, integer for the month, and an integer for the day. calendar:valid_date/3 returns the atom true if the day passed in is a valid date, and the atom false if it is not a valid date.

calendar:valid_date(2015, 04, 31).
% false
calendar:valid_date(2015, 04, 30).
% true
calendar:valid_date(2015, 02, 29).
% false
calendar:valid_date(2012, 02, 29).
% true
calendar:valid_date(2015, 11, 31).
% false
calendar:valid_date(2015, 11, 76).
% false
calendar:valid_date(2015, 17, 13).
% false

Just a quick check for our sanity that the day this post was published is a valid date as well.

calendar:valid_date(2015, 04, 23).
% true

Now let’s try to break this a bit and test to see how it can handle 0‘s and negative integer values.

calendar:valid_date(-1, 04, 23).
% false
calendar:valid_date(2015, -7, 21).
% false
calendar:valid_date(2015, 7, -13).
% false
calendar:valid_date(0, 0, 0).
% false

As one might hope, unless you deal with B.C. era dates often, a date with a negative value is not a valid date.

Erlang also provides a calendar:valid_date/1 that takes a tuple of the year, month, and day values as well.

calendar:valid_date({2015, 11, 76}).
% false
calendar:valid_date({2015, 04, 23}).
% true

–Proctor

Erlang Thursday – calendar:date_to_gregorian_days/3

Today’s Erlang Thursday covers calendar:date_to_gregorian_days/3.

As we saw in last week’s Erlang Thursday on calendar:day_of_the_week/3 when we were looking at some error messages, we saw that the errors were coming from calendar:date_to_gregorian_days/3.

calendar:day_of_the_week(0, 0, 0).
% ** exception error: no function clause matching calendar:date_to_gregorian_days(0,0,0) (calendar.erl, line 114)
%      in function  calendar:day_of_the_week/3 (calendar.erl, line 151)
calendar:day_of_the_week(1970, 2, 31).
% ** exception error: no true branch found when evaluating an if expression
%      in function  calendar:date_to_gregorian_days/3 (calendar.erl, line 116)
%      in call from calendar:day_of_the_week/3 (calendar.erl, line 151)
calendar:day_of_the_week(1970, 13, 2).
% ** exception error: no function clause matching calendar:last_day_of_the_month1(1970,13) (calendar.erl, line 243)
%      in function  calendar:date_to_gregorian_days/3 (calendar.erl, line 115)
%      in call from calendar:day_of_the_week/3 (calendar.erl, line 151)

I promised you at the end of that post we would take a deeper look at calendar:date_to_gregorian_days/3 next time, so let’s fulfill that promise.

calendar:date_to_gregorian_days/3 takes three arguments, a non-negative integer for the year, an integer between 1 and 12 (inclusive) for the month, and an integer between 1 and 31 (inclusive) for the day of the month, and returns the number of days since 0000-01-01 in the Gregorian calendar.

calendar:date_to_gregorian_days(2015, 4, 16).
% 736069
calendar:date_to_gregorian_days(0, 1, 1).
% 0
calendar:date_to_gregorian_days(1, 1, 1).
% 366
calendar:date_to_gregorian_days(1970, 1, 1).
% 719528
calendar:date_to_gregorian_days(1999, 12, 31).
% 730484

There is also a version calendar:date_to_gregorian_days/1, that takes a tuple of year, month, and day available if your code already has the date in tuple format.

calendar:date_to_gregorian_days({2015, 4, 16}).
% 736069
calendar:date_to_gregorian_days({0, 1, 1}).
% 0
calendar:date_to_gregorian_days({1, 1, 1}).
% 366

And if we pass something invalid to calendar:date_to_gregorian_days/1, we see that it is calling calendar:date_to_gregorian_days/3. So it is just a nice helper function that does the pattern match destructing for us.

calendar:date_to_gregorian_days({1, 1, 0}).
** exception error: no function clause matching calendar:date_to_gregorian_days(1,1,0) (calendar.erl, line 114)

–Proctor