Functions in Elixir

Sunday, 8th November, 2015

** defined functions

Functions are defined within a module.

Note that definition syntax and usage behaviour is slightly different depending on whether the function has a single argument or several arguments. For example, a space between function name and arguments is acceptable for a single-argument function, but is a syntax error with a multi-argument function:

def clown2a(x) do 5 * x end  # ok

def clown2b (x) do 5 * x end  # ok

def clown2b x do 5 * x end  # ok

def clown3a(x,y) do x + y end  # ok

def clown3b (x,y) do x + y end  # syntax error

def clown3c x,y   do x + y end  # ok

Similarly when using functions:

iex(1)> Drop.clown2a(5)

iex(2)> Drop.clown2a (5)

iex(3)> Drop.clown3a(5,6)

iex(4)> Drop.clown3a (5,6)
** (SyntaxError) iex:81: unexpected parentheses. If you are making
a function call, do not insert spaces between the function name
and the opening parentheses. Syntax error before: '('

There is also an optional short form of function definition which uses the construction “, do:” instead of “do” and omits “end”. This form can be used if the function body fits on one line, e.g.:

[7]  def clown4b(x,y), do: x + y 

[8]  def clown4b(x,y), do:
         x + y

Note that this short form is much stricter about spaces and brackets, but does still allow some creativity and individualism for the programmer:

def clown4d (x,y), do:  x + y  
# syntax error - space after function name

def clown4e x,y,   do:  x + y  
# syntax error - no brackets round arguments

def clown4c(x,y),  do:x + y    
# syntax error - no space after "do:"

def clown4h(x,y) , do : x + y  
# syntax error - space between "do" and ":"

def clown4f(x,y) , do:  x + y  # ok - space around ","

def clown4g(x,y)  ,do:  x + y  # ok - no space after ","

Functions defined above are available in this gist. They are based on code from the O’Reilly book “Introducing Elixir”.

** anonymous functions

In the shell only anonmyous functions can be used, e.g. bound to a variable.

Anonymous functions seem to behave similarly in the shell and in modules.

Anonymous functions do not behave quite the same as “defined” functions.

*** remember the extra dot

When using a bound anonymous function you must add an extra dot between the function name and its arguments:

 iex(1)> ad5 = fn(x) -> 5+x end
 iex(2)> ad5(9)
 ** (CompileError) iex:94: undefined function ad5/1 

 iex(3)> ad5.(9)

*** optional spaces almost everywhere, almost like defined functions

As with defined functions, there are lots of options for adding whitespace — but not quite the same options:

**** one parameter

 iex(4)> a5b = fn (x) -> 5+x end
 iex(5)> a5b.(9)
 iex(6)> a5b. (9)
 iex(7)> a5b. 9
 ** (SyntaxError) iex:7: syntax error before: 9

 # cf:
 iex(8)> :math.sqrt(9)
 iex(9)> :math.sqrt (9)
 iex(10)> :math.sqrt 9

*** two parameters

 iex(11)> sma = fn(x,y) -> x+y end
 iex(12)> smb = fn (x,y) -> x+y end
 iex(13)> smc = fn x,y -> x+y end
 iex(14)> smc.(4,5)
 iex(15)> smc. (4,5)
 iex(16)> smc. 4,5
 ** (SyntaxError) iex:14: syntax error before: 4

cf similar defined functions in a module:

defmodule Clown do

  def clown3a(x,y)  do IO.puts(x+y) end
# def clown3b (x,y) do IO.puts(x+y) end  # syntax error
  def clown3c x,y   do IO.puts(x+y) end


Running this module:

 iex(17)> Drop.clown3a(5,6)
 iex(18)> Drop.clown3a (5,6)
 ** (SyntaxError) iex:81: unexpected parentheses. If you are making a
 function call, do not insert spaces between the function name and
 the opening parentheses. Syntax error before: '('
 iex(19)> Drop.clown3a 5,6

Command #15 is ok but command #18 is a syntax error;
Command #16 is a syntax error but command #19 is ok.

*** short version

There is also a short version of the anonymous function, in which the arity is implicit:

 iex(20)> clownx = &(&1 + &2)
 iex(21)> clownx. (4,5)
 iex(22)> clownx. (4,5,6)
 ** (BadArityError) &:erlang.+/2 with arity 2 called with 3 arguments (4, 5, 6)
 iex(23)> clowny = &(&1 + &3)
 ** (CompileError) iex:3: capture &3 cannot be defined without &2
     (elixir) src/elixir_fn.erl:123: :elixir_fn.validate/4
     (elixir) src/elixir_fn.erl:112: :elixir_fn.do_capture/4

The module compiler does do some of this checking. In the module below, the commented-out function c1a would be blocked by the compiler, but function c1b will not be. At runtime, the running process will crash when it reaches line 10.

 defmodule Anon do
 #  def c1a(x,y,z) do
 #   f = &(&1 + &3)  # syntax error blocked by compiler
 #   f. (x,y,z)
 #  end
   def c1b(x,y,z) do
    f = &(&1 + &2)
    f. (x,y,z)

For example:

 iex(24)> c("anon.ex")
 iex(25)> Anon.c1b(2,3,4)
 ** (BadArityError) &:erlang.+/2 with arity 2 called with 3 arguments (2, 3, 4)
     anon.ex:10: Anon.c1b/3

Erlang and SMTP: a quick round-up

Sunday, 18th October, 2015

[update 20151022: added selectel/pat]

There seem to be three live projects for using SMTP from erlang:

  • Richard Carlsson’s sendmail
  • the smtp module in Yaws
  • Vagabond’s gen_smtp
  • Selectel’s pat

** Richard Carlsson’s sendmail

This is a simple-but-useful wrapper round sendmail. Consequently, it depends on the host OS having sendmail up & running. Also consequently, it can take advantage of sendmail’s other features (e.g., retrying failed sends). As Richard explained on erlang-questions in 2011:

Often, what you want is more than just SMTP. If there are some network
issues (or your mail server is simply down) at the time your program
tries to send the mail, you usually want your program to still be able
to regard the mail as sent and carry on. This means that the mail needs
to be persistently stored on disk in a spool area and that the MTA
regularly tries to send any outgoing mail that’s been spooled, so it
will eventually be on its way once the problem is resolved. That’s why
we like to rely on sendmail instead. But it all depends on the needs of
your application.

Note: although this is a single script, it is a git repo in its own right, so it can be added as a dependency.

However, as it’s a single-script it doesn’t have anything fancy like a Makefile. I’ve created a fork with a Makefile so I can have it in my Makefile as a dependency:

** the smtp module in Yaws

This is a single-script smtp client for sending emails. It does not depend on (or use) sendmail.

It seems that, to add this as a dependency to a project, it would be necessary to either add Yaws itself as a dependency, or manually copy the smtp.erl script into your own project.

** Vagabond’s gen_smtp

This is the full Monty: “a generic Erlang SMTP server framework that can be extended via callback modules in the OTP style. A pure Erlang SMTP client is also included.”

** Selectel’s pat

This connects to a downstream SMTP server to send email messages. An email message is represented by an erlang record.

Draggable-Droppable Sortable List

Friday, 18th September, 2015

Here is a demo showing Rubaxa’s Sortable used with React.

The demo is based on a trimmed down version of the React example on the Sortable github page. The extras are:

  • the list items are React classes rather than text;
  • handleEnd shows accessing re-arranged list items on drop;
  • list items have a handle, which means their contents can be assessed and manipulated.

n.b.: in the gist below, the javascript file uses JSX markup so it’ll need to be compiled (e.g. with React’s cli tools or babel).

[github gist]

I like Rubaxa’s Sortable because it (a) works! (b) does not require any silly javascript package managers.

I recently did the Elm: Building Reactive Web Apps video course by The Pragmatic Studio ($29). Here are some notes about my experience.

I enjoyed the course, and I think I learned a lot. I shall certainly be taking the Elm: Signals, Mailboxes, & Ports course when it comes out in mid-September.

The course was two hours of videos in twenty six-minute sessions. Source code and pdf summaries also available.

It used a simple project to cover the basics of

This was plenty, and made for a relaxed, uncluttered course. Presentation was clear and unfussy.

Using the StartApp module meant that the details of message-passing in Elm could be left out altogether. I think it is a good idea to treat message-passing as a topic in its own right (i.e., which they’ll be covering in their next course).

I liked the course a lot and I highly recommend it.

Brief review: The Little MLer

Sunday, 31st May, 2015

book details

“The Little MLer”
Matthias Felleisen and Daniel P. Friedman
MIT Press


I had resolved not to learn any new languages in 2015, but: I knew if I were to learn a language it would probably be ML (or some kind of proof assistant type thing); this book was on my Amazon Wish List; and MIT Press had a half price sale.

I’m afraid I was quite underwhelmed by The Little MLer. It brings upon itself comparison with The Little Schemer: the same dialogue format, the same illustrator (with “guest appearances” by the Little Schemer elephants), even occasional “in-jokes” about Lisp. It suffers greatly under this comparison.

Lisp is not a normal programming language. The basic building blocks of Lisp — list; first thing in list; rest of list — are so simple — naively, childishly simple, even romantically simple (steady on — Ed.). So the childish dialogue approach in The Little Schemer, with virtually no presuppositions really is plausible, and even appropriate. I thought the book effectively conveyed the charm and wonder of Lisp.

I’m not qualified to say much sensible about ML, but this book felt contrived — the tried and tested dialogue format forced onto an unsuspecting programming language (in the same style there’s also A Little Java and A Few Patterns). The Little Schemer was full of “stout Cortez” moments; The Little MLer had one: a brief exploration of what might have been lazy evaluation.

I have a gut feeling that ML could be an exciting language, but The Little MLer is a dull exposition following an imported schema.

My plan for this year is to bring in the clients, write the apps, and make some money. Being anything other than ruthlessly pragmatic about learning new programming languages is distinctly not part of the plan. This year is about focussing and consolidating, it is not about wandering about smelling the roses.

However, …

Separate from programming, I am following up some of my reading from last year. In particular, Hegel (I’m finally tackling his Phenomenology of Spirit) and Schrödinger (his book and Weyl’s book both look worth a try; and Schrödinger’s paper on colour looks like it might be a good introduction to some of the geometry).

Learning about the strong link between Schrödinger and Weyl was quite a revelation. Weyl was also associated with Brouwer and the intuitionist/constructivist approach to maths. The ncatlab page on constructive maths mentions Hegel in its prehistory section.

So, sometime later in the year I’ll be reading about Brouwer, his mathematical intuitionism, and constructivism. As part of that, I might be “doing” some maths.

Doing constructive maths seems to involve proofs, verifications of proofs, and even mechanisations of verifications. Things called proof assistants can be used. So quite possibly I’ll be trying out one or more of these proof assistants.

To the untrained eye these proof assistant things look a lot like programming languages.

That Giant’s Causeway puzzle in Prolog

Tuesday, 13th January, 2015

Chris Lamb published a very nice blog post the other day showing a wooden logic puzzle he’d found, and implementing a solver in Python.

It was such a nice post I thought I’d write one in Prolog. Here it is (and in a gist):

% hex tiles puzzle
% -
% -

:- use_module(library(clpfd)).  %% for all_different/1

%% tile(Name, Colours).

% tiles from picture
% tile(11, [red, blue, black, yellow, green, white]).
% tile(22, [white, black, yellow, green, blue, red]).
% tile(33, [green, blue, black, yellow, red, white]).
% tile(44, [white, black, red, green, blue, yellow]).
% tile(55, [white, blue, green, yellow, black, red]).
% tile(66, [white, yellow, red, blue, black, green]).
% tile(77, [red, yellow, green, black, blue, white]).

% re-jigged a bit
tile(11, [white, black, red, green, blue, yellow]).
tile(22, [white, black, yellow, green, blue, red]).
tile(33, [white, blue, green, yellow, black, red]).
tile(44, [white, green, blue, black, yellow, red]).
tile(55, [white, red, blue, black, yellow, green]).
tile(66, [white, red, yellow, green, black, blue]).
tile(77, [white, yellow, red, blue, black, green]).

%% only six rotations allowed


%% rotate(List1, NStepsAntiClockwise, List2). 

rotate(Cs, 0, Cs).
rotate([A,B,C,D,E,F], 1, [B,C,D,E,F,A]).
rotate([A,B,C,D,E,F], 2, [C,D,E,F,A,B]).
rotate([A,B,C,D,E,F], 3, [D,E,F,A,B,C]).
rotate([A,B,C,D,E,F], 4, [E,F,A,B,C,D]).
rotate([A,B,C,D,E,F], 5, [F,A,B,C,D,E]).

%% colour(Name, Rotation, Position, Colour).

colour(N, R, P, C):-
    tile(N, Cs),
    X is (P + R) mod 6,
    nth0(X, Cs, C).

same_colour(N1, R1, P1, N2, R2, P2):-
    colour(N1, R1, P1, C),
    colour(N2, R2, P2, C).

solve(N1, R1, N2, R2, N3, R3, N4, R4, N5, R5, N6, R6, N7, R7):-
    all_different([N1, N2, N3, N4, N5, N6, N7]),

    same_colour(N1, R1, 3, N2, R2, 0),
    same_colour(N1, R1, 4, N4, R4, 1),
    same_colour(N1, R1, 5, N3, R3, 2),
    same_colour(N2, R2, 4, N5, R5, 1),
    same_colour(N2, R2, 5, N4, R4, 2),
    same_colour(N3, R3, 3, N4, R4, 0),
    same_colour(N3, R3, 4, N6, R6, 1),
    same_colour(N4, R4, 3, N5, R5, 0),
    same_colour(N4, R4, 4, N7, R7, 1),
    same_colour(N4, R4, 5, N6, R6, 2),
    same_colour(N5, R5, 5, N7, R7, 2),
    same_colour(N6, R6, 3, N7, R7, 0).

show(N, R):-
    tile(N, Cs),
    rotate(Cs, R, Rs),
    format("~d    ~w~n", [N, Rs]).

    solve(N1, R1, N2, R2, N3, R3, N4, R4, N5, R5, N6, R6, N7, R7),
    show(N1, R1),
    show(N2, R2),
    show(N3, R3),
    show(N4, R4),
    show(N5, R5),
    show(N6, R6),
    show(N7, R7).

Get every new post delivered to your Inbox.