Is infix lambda hard to read?

I've been using infix lambda in pseudocode for a couple of years, with mixed results. I find it very easy to write, because it's so terse, and I tend to use it for any one-argument function I can't get by partial application and simple combinators. But I find it surprisingly hard to read.

The symptom is that I mistake the parameter list for an expression. For example, in a definition like this...

gravitate bodies = map (b → accelerate b (field b bodies)) bodies

...I sometimes read the first b as a free variable, and spend a confused moment trying to figure out where it's bound, before I notice the operator and realize that I'm looking at the binding occurrence. This mistake is especially easy to make in larger definitions, where it's not obvious the b doesn't refer to some local variable I've forgotten about — and where it takes longer to see that no such variable exists.

I think the underlying problem is that the parameter list is the left argument of , so when I read an expression left-to-right, I encounter it before the operator. Since I haven't yet seen any hint that it's not an expression, I try to read it as one, and fail. Ordinary lambda, in constrast, announces its specialness first, so I'm not surprised by the parameter list.

If this really is the problem, then it should also affect other operators whose left arguments aren't expressions. But there aren't many. The only one I can think of is the ubiquitous (in my pseudocode, at least) infix define, =, which may be less confusing because it's used in distinctive contexts (at top level or in a progn). There are a few common operators whose right arguments are special (e.g. . for field access), but it seems few infix operators have left arguments that aren't expressions.

What do C♯ users (at least those few who use lambda much) think? Do you have trouble reading =>?

3 comments:

  1. I actually have more reading difficulty with the prefix lambda λx (or \x). It may be related to whether or not parentheses are required in method invocations, and whether commas are expected between arguments. When you have a C-like foo(a, b, c), it's no great shakes to have foo(a => a * 2, b, c) - here, you need look only one lexeme over to see the lambda. Similarly, foo((a, b) => a * b, c, d) is similarly clear - (a, b) can only be a lambda parameter list in idiomatic C#.

    ReplyDelete
  2. I work in C# regularly and I have struggled with this as well. The moment of confusion when I first hit the variable is bad, but what is worse are the whiteboard situations when I find myself writing code for people and explaining an idea. I really want the lambda to come first while I'm talking. I find a spoken explanation does not flow while when the infix lambda is used. When possible I even switch to languages with prefix lambda when I need to write code for a group.

    ReplyDelete
  3. I, too, find it hard to read.

    ReplyDelete

It's OK to comment on old posts.