views:

890

answers:

10

I recently started studying functional programming using Haskell and came upon this article on the official Haskell wiki: How to read Haskell.

The article claims that short variable names such as x, xs, and f are fitting for Haskell code, because of conciseness and abstraction. In essence, it claims that functional programming is such a distinct paradigm that the naming conventions from other paradigms don't apply.

What are your thoughts on this?

+22  A: 

In a functional programming paradigm, people usually construct abstractions not only top-down, but also bottom-up. That means you basically enhance the host language. In this kind of situations I see terse naming as appropriate. The Haskell language is already terse and expressive, so you should be kind of used to it.

However, when trying to model a certain domain, I don't believe succinct names are good, even when the function bodies are small. Domain knowledge should reflect in naming.

Just my opinion.

In response to your comment

I'll take two code snippets from Real World Haskell, both from chapter 3.

In the section named "A more controlled approach", the authors present a function that returns the second element of a list. Their final version is this:

tidySecond :: [a] -> Maybe a
tidySecond (_:x:_) = Just x
tidySecond _       = Nothing

The function is generic enough, due to the type parameter a and the fact we're acting on a built in type, so that we don't really care what the second element actually is. I believe x is enough in this case. Just like in a little mathematical equation.

On the other hand, in the section named "Introducing local variables", they're writing an example function that tries to model a small piece of the banking domain:

lend amount balance = let reserve    = 100
                          newBalance = balance - amount
                      in if balance < reserve
                         then Nothing
                         else Just newBalance

Using short variable name here is certainly not recommended. We actually do care what those amounts represent.

Ionuț G. Stan
I think I understand what you mean, but could you provide an example of the difference between the two situations, just in case?
Jakob
@Jakob Many functional languages use some variant of the Hindley-Milner type system, where it is very easy to write generic functions and data structures. In this situation, when programming the data structure, you have no reason to name keys and values in your map, say, "studentId" and "studentFile", so you simply name them "key" and "value", or even "k" and "v" (another common convention).
Pascal Cuoq
In the first case using X is similar to using i as a for loop counter in C. It is more or less a throw away variable a longer name would harm meaning not help it. In the second case they are actual variables with actual meaning, so good names are important.
stonemetal
The built-in snd function actually only works on tuples of size 2. The function they're reimplementing in RWH is (!! 1).
yatima2975
@yatima2975, thanks! I somehow mixed things up while writing the answer.
Ionuț G. Stan
+6  A: 

I think scoping is the #1 reason for this. In imperative languages, dynamic variables, especially global ones need to be named properly, as they're used in several functions. With lexical scoping, it's clear what the symbol is bound to at compile time.

Immutability also contributes to this to some extent- in traditional languages like C/ C++/ Java, a variable can represent different data at different points in time. Therefore, it needs to be given a name to give the programmer an idea of its functionality.

Personally, I feel that features features like first-class functions make symbol names pretty redundant. In traditional languages, it's easier to relate to a symbol; based on its usage, we can tell if it's data or a function.

Ramkumar Ramachandra
+1  A: 

Anything that aids readability is a good thing - meaningful names are therefore a good thing in any language.

I use short variable names in many languages but they're reserved for things that aren't important in the overall meaning of the code or where the meaning is clear in the context.

I'd be careful how far I took the advice about Haskel names

Chris McCauley
+5  A: 

I'm studying Haskell now, but I don't feel that its naming conventions is so very different. Of course, in Java you're hardly to find a names like xs. But it is easy to find names like x in some mathematical functions, i, j for counters etc. I consider such names to be perfectly appropriate in right context. xs in Haskell is appropriate only generic functions over lists. There's a lot of them in Haskell, so this name is wide-spread. Java doesn't provide easy way to handle such a generic abstractions, that's why names for lists (and lists themselves) are usually much more specific, e.g. lists or users.

Rorick
+13  A: 

I think if the semantics of the arguments are clear within the context of the code then you can get away with short variable names. I often use these in C# lambdas for the same reason. However if it is ambiguous, you should be more explicit with naming.

map                     :: (a->b) -> [a] -> [b]
map f  []               =  []
map f (x:xs)            =  f x : map f xs

To someone who hasn't had any exposure to Haskell, that might seem like ugly, unmaintainable code. But most Haskell programmers will understand this right away. So it gets the job done.

var list = new int[] { 1, 2, 3, 4, 5 };
int countEven = list.Count(n => n % 2 == 0)

In that case, short variable name seems appropriate.

list.Aggregate(0, (total, value) => total += value);

But in this case it seems more appropriate to name the variables, because it isn't immediately apparent what the Aggregate is doing.

Basically, I believe not to worry too much about convention unless it's absolutely necessary to keep people from screwing up. If you have any choice in the matter, use what makes sense in the context (language, team, block of code) you are working, and will be understandable by someone else reading it hours, weeks or years later. Anything else is just time-wasting OCD.

Dale Halliwell
Very good points. Functional languages tend to have more single-letter-conventions for variables that tell the accustomed reader what to expect immediately (Brian mentions x, i, and f).For some odd reason conventions vary from language to language when they don't need to. You would see "head::tail" or just "h::t" in OCaml instead of "x:xs". Also, the emacs caml-mode can display infered types, so there is less need to put *that* information in the variable name. I expect other functional languages have a similar feature.
Pascal Cuoq
Isn't it just `(total, value) => total + value` ;) Quite an irony to have unintended mutation in a functional programming context...
Dario
+4  A: 

I just attended a number of talks on Haskell with lots of code samples. As longs as the code dealt with x, i and f the naming didn't bother me. However, as soon as we got into heavy duty list manipulation and the like I found the three letters or so names to be a lot less readable than I prefer.

To be fair a significant part of the naming followed a set of conventions, so I assume that once you get into the lingo it will be a little easier.

Fortunately, nothing prevents us from using meaningful names, but I don't agree that the language itself somehow makes three letter identifiers meaningful to the majority of people.

Brian Rasmussen
When you see `foo bar (x:xs) = bar x : foo bar xs`, isn't it immediately clear that you're looking at a map function? I think this is much more clear than similarly "vague" variable names would be in most imperative languages.
Chuck
@Chuck: Actually, only `foo` and `bar` are vague. `x:xs` is idiomatic, so Haskell programmers will know exactly what you mean.
Jørgen Fogh
+1  A: 

When in Rome, do as the Romans do

(Or as they say in my town: "Donde fueres, haz lo que vieres")

fortran
,............do
Stimul8d
+1  A: 

My Haskell practice is only of mediocre level, thus, I dare to try to reply only the second, more general part of Your question:

"In essence, it claims that functional programming is such a distinct paradigm that the naming conventions from other paradigms don't apply."

I suspect, the answer is "yes", but my motivation behind this opinion is restricted only on experience in just one single functional language. Still, it may be interesting, because this is an extremely minimalistic one, thus, theoretically very "pure", and underlying a lot of practical functional languages.

I was curios how easy it is to write practical programs on such an "extremely" minimalistic functional programming language like combinatory logic.

Of course, functional programming languages lack mutable variables, but combinatory logic "goes further one step more" and it lacks even formal parameters. It lacks any syntactic sugar, it lacks any predefined datatypes, even booleans or numbers. Everything must be mimicked by combinators, and traced back to the applications of just two basic combinators.

Despite of such extreme minimalism, there are still practical methods for "programming" combinatory logic in a neat and pleasant way. I have written a quine in it in a modular and reusable way, and it would not be nasty even to bootstrap a self-interpreter on it.

For summary, I felt the following features in using this extremely minimalistic functional programming language:

  • There is a need to invent a lot of auxiliary functions. In Haskell, there is a lot of syntactic sugar (pattern matching, formal parameters). You can write quite complicated functions in few lines. But in combinatory logic, a task that could be expressed in Haskell by a single function, must be replaced with well-chosen auxiliary functions. The burden of replacing Haskell syntactic sugar is taken by cleverly chosen auxiliary functions in combinatory logic. As for replying Your original question: it is worth of inventing meaningful and catchy names for these legions of auxiliary functions, because they can be quite powerful and reusable in many further contexts, sometimes in an unexpected way.

  • Moreover, a programmer of combinatory logic is not only forced to find catchy names of a bunch of cleverly chosen auxiliary functions, but even more, he is forced to (re)invent whole new theories. For example, for mimicking lists, the programmer is forced to mimick them with their fold functions, basically, he has to (re)invent catamorphisms, deep algebraic and category theory concepts.

I conjecture, several differences can be traced back to the fact that functional languages have a powerful "glue".

physis
+1  A: 

In Haskell, meaning is conveyed less with variable names than with types. Being purely functional has the advantage of being able to ask for the type of any expression, regardless of context.

Apocalisp
A: 

I agree with a lot of the points made here about argument naming but a quick 'find on page' shows that no one has mentioned Tacit programming (aka pointfree / pointless). Whether this is easier to read may be debatable so it's up to you & your team, but definitely worth a thorough consideration.

No named arguments = No argument naming conventions.

Tim Matthews