lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Mon, Feb 27, 2012 at 6:38 AM, steve donovan
<steve.j.donovan@gmail.com> wrote:
> On Mon, Feb 27, 2012 at 2:49 AM, Miles Bader <miles@gnu.org> wrote:
>> In this case, the point seems to be reducing the size and visual impact
>> of small lambdas, which suggests not using a keyword would be better.
>
> Yes, but there was a surprising backlash against short lambda forms.
> There is a great fear that Lua could become Perl, and degenerate into
> line noise.  (I appreciate that the functional style is not everyone's
> cup of tea, however.)
[...]
> I like a variant on the Metalua syntax:  |x|(x+1).

Anecdotes about line noise aside[1], there are a couple interesting
fears hiding in here.

One is it's the start of land-rush to colonize all remaining ASCII
punctuation. This is a slippery-slope argument. Although I've got my
bid in for one character in one lexical context (directly preceding
string literals) I think there is little danger of sliding down that
slope. I'm trying to remember (without looking) what the "(| x() |)"
and "(> x() <)" syntax meant in one language I worked on--one of them
was pcall...

The power of the "what *does* that string do as a TECO command/perl
expression" put-down is that TECO and perl4 assigned meaning to large
chunks of  L = /.*/. If everything is legal, error detection becomes
difficult, especially for diagnosis at the point of misuse. I think
lhf's [[ \x(x+1) ]] and Steve's' [[ |x|(x+1) ]] proposals to
parenthesize the expression will limit damage, and we're already
familiar with unclosed paren problems.

The whole point of terse lambda syntax is to encourage new control
flow. For amb, thunking all the arguments allows evaluation to be
performed later; in Lua you'd write [[ amb( ||(1+f()), ||(g()) ) ]]
instead of the Lua-with-macros [[ amb( 1+f(), g() ) ]]. A lot of
places macros look useful are also places where lexical scoping and
procedure constructors (aka lambdas) allow 80% of the job to be done.
So if the underlying objection is to proliferation of control flow not
obvious to local inspection, well, that's a dead stop.

If you'd like something to be afraid of, fear becoming Smalltalk-80 or
Ruby. All of Smalltalk's control flow is built with lambdas aka blocks
making

  1>5 ifTrue: [ lose ] ifFalse: [ win ]

look like this in lua:

  (1>5):ifTrueIfFalse( ||( lose ), ||( win ) )

This means anybody can write their own control flow whenever they feel
like it, and when combined with the Perl philosophy of "if syntax or
semantics are ambiguous, try to pick the most useful way of repairing
it" you get Ruby. To be clear, the ability to write domain-specific
control forms in an idiomatic way make Smalltalk and Ruby better
language construction sets. I think the combination of Lua's natural
list constructor syntax with terse lambdas gets interesting but not
too interesting. Something like Dirk's @->function, !->end suggestion
allows statements, which gives a very natural switch statement--but
maybe that's a bridge too far too.

Finally, there's the fear that we're going to be seeing
Y-combinator-style logic edge out good old imperative control flow
because it's shorter to type. Let's hit wikipedia:

(define Y
  (lambda (f)
    ((lambda (recur) (f (lambda arg (apply (recur recur) arg))))
     (lambda (recur) (f (lambda arg (apply (recur recur) arg)))))))

Well then:

function Y(f)
  return |recur|( f( |x|(recur(recur)(x)))( |recur| (f( |x|(recur(recur)(x))) )
end

OK, you know it's Monday morning when you keep running out of
attention span before you can transform an AST from one surface syntax
to a similar one, much less check it, much much less remember how it
works. And it's Monday morning all the time lately. I give up, that
example's probably wrong. How about:

function forever(f)
  local v
  while true do
    v = f(v)
  end
end

Abuse of function application is fun. Really, this ship has already sailed:

function struct(name)
  return function(body)
    for k,v in pairs(body) do
      print(name.."."..k, v)
    end
  end
end

struct "ColoredPoint" {
  x="int32";
  y="int32";
  rgb="Color";
}

...which blew my mind when it first showed up on the list.

Jay

[1]: Around 1994 or so we were trying to scrounge up remote access for
a colleague, who had gone directly from home computers to CMU's
workstations. No PC available to take home, but we did have a spare
terminal. "What's a terminal?" Well...it's a computer that just runs
one xterm. "Oh, OK, I do everything in Emacs anyway," she said. At
least we have error-correcting modems, so there won't be any line
noise. "What's line noise?" ...hmm. I'm glad you don't have to know.
Don't ask.