Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an idiomatic way to order function arguments in Erlang?

Tags:

erlang

Seems like it's inconsistent in the lists module. For example, split has the number as the first argument and the list as the second, but sublists has the list as the first argument and the len as the second argument.

like image 280
pjb3 Avatar asked Nov 24 '09 04:11

pjb3


People also ask

How many parameters can Erlang functions have?

Erlang functions can be defined with zero or more parameters. Function overloading is also possible, wherein you can define a function with the same name multiple times, as long as they have different number of parameters. In the following example, the function demo is defined with multiple arguments for each function definition.

How to get the first element of a list in Erlang?

The first function we'll write is head/1, acting exactly like erlang:hd/1 which takes a list as an argument and returns its first element. It'll be done with the help of the cons operator ( | ): view source print? 1.

What are higher order functions in Erlang?

Higher order functions are a powerful means of abstraction and one of the best tools to master in Erlang. Again, this a concept rooted in mathematics, mainly lambda calculus. I won't go into much detail about lambda calculus because some people have a hard time grasping it and it's a bit out of scope.

What is the_character used for in Erlang?

The _ character can be used whenever you don't care about the value of a result, we use it here because we know anything valid has been matched by the function definition directly above. In Erlang, functions are always matched from top to bottom.


2 Answers

OK, a little history as I remember it and some principles behind my style.

As Christian has said the libraries evolved and tended to get the argument order and feel from the impulses we were getting just then. So for example the reason why element/setelement have the argument order they do is because it matches the arg/3 predicate in Prolog; logical then but not now. Often we would have the thing being worked on first, but unfortunately not always. This is often a good choice as it allows "optional" arguments to be conveniently added to the end; for example string:substr/2/3. Functions with the thing as the last argument were often influenced by functional languages with currying, for example Haskell, where it is very easy to use currying and partial evaluation to build specific functions which can then be applied to the thing. This is very noticeable in the higher order functions in lists.

The only influence we didn't have was from the OO world. :-)

Usually we at least managed to be consistent within a module, but not always. See lists again. We did try to have some consistency, so the argument order in the higher order functions in dict/sets match those of the corresponding functions in lists.

The problem was also aggravated by the fact that we, especially me, had a rather cavalier attitude to libraries. I just did not see them as a selling point for the language, so I wasn't that worried about it. "If you want a library which does something then you just write it" was my motto. This meant that my libraries were structured, just not always with the same structure. :-) That was how many of the initial libraries came about.

This, of course, creates unnecessary confusion and breaks the law of least astonishment, but we have not been able to do anything about it. Any suggestions of revising the modules have always been met with a resounding "no".

My own personal style is a usually structured, though I don't know if it conforms to any written guidelines or standards.

I generally have the thing or things I am working on as the first arguments, or at least very close to the beginning; the order depends on what feels best. If there is a global state which is chained through the whole module, which there usually is, it is placed as the last argument and given a very descriptive name like St0, St1, ... (I belong to the church of short variable names). Arguments which are chained through functions (both input and output) I try to keep the same argument order as return order. This makes it much easier to see the structure of the code. Apart from that I try to group together arguments which belong together. Also, where possible, I try to preserve the same argument order throughout a whole module.

None of this is very revolutionary, but I find if you keep a consistent style then it is one less thing to worry about and it makes your code feel better and generally be more readable. Also I will actually rewrite code if the argument order feels wrong.

A small example which may help:

fubar({f,A0,B0}, Arg2, Ch0, Arg4, St0) ->
    {A1,Ch1,St1} = foo(A0, Arg2, Ch0, St0),
    {B1,Ch2,St2} = bar(B0, Arg4, Ch1, St1),
    Res = baz(A1, B1),
    {Res,Ch2,St2}.

Here Ch is a local chained through variable while St is a more global state. Check out the code on github for LFE, especially the compiler, if you want a longer example.

This became much longer than it should have been, sorry.

P.S. I used the word thing instead of object to avoid confusion about what I was talking.

like image 150
rvirding Avatar answered Nov 16 '22 01:11

rvirding


No, there is no consistently-used idiom in the sense that you mean.

However, there are some useful relevant hints that apply especially when you're going to be making deeply recursive calls. For instance, keeping whichever arguments will remain unchanged during tail calls in the same order/position in the argument list allows the virtual machine to make some very nice optimizations.

like image 22
Justin Sheehy Avatar answered Nov 16 '22 03:11

Justin Sheehy