fun with table constructors

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

fun with table constructors

John Belmonte-2
In Lua the f{...}syntax (syntactic sugar for f({...})) is useful for data description:

    SomeType {
        1,
        2,
        3,
    }

What if we want to allow the user to name this list data?  One way is like this:

    SomeType {
        name = "abc";
        1,
        2,
        3,
    }

But that requires the user to remember to use ';' and do extra typing, and exposes internals of
the implementation.  A syntax like this may be preferable:

    SomeType "abc" {
        1,
        2,
        3,
    }

This can be done in Lua with a wrapping function that takes the name and generates a real
constructor.   Here is an example:

    function SomeType(name)
        return function(t)
            t.name = %name
            return t
        end
    end


-John



Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Reuben Thomas-3
> the implementation.  A syntax like this may be preferable:
>
>     SomeType "abc" {
>         1,
>         2,
>         3,
>     }

i.e. currying! Lovely. The only problem is that this only works with strings
and tables, not numbers. If only we were allowed to have:

f 3  => f(3)

then we could write

function plus(a) return function (b) return %a + b end end

plus 3 4

...but this is not legal syntax. You have to write plus(3), and then can't
apply the result directly to 4, so you need:

a = plus(3)
a(4)

blech.

One other annoyance is that you can't directly apply an anonymous function:

(function (x) print(x) end) "hello"

is illegal.

-- 
http://sc3d.org/rrt/ | computation, n.  automated pedantry


Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Roberto Ierusalimschy
> You have to write plus(3), and then can't apply the result directly to 4

You can, as long as you use the parentheses: plus(3)(4) is legal syntax.


> One other annoyance is that you can't directly apply an anonymous function:
> 
> (function (x) print(x) end) "hello"

You can write «Id(function (x) print(x) end) "hello"» (where Id is the
identity function), but I agree this is a little inconvenient.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Luiz Henrique de Figueiredo
In reply to this post by John Belmonte-2
>> One other annoyance is that you can't directly apply an anonymous function:
>> 
>> (function (x) print(x) end) "hello"
>
>You can write «Id(function (x) print(x) end) "hello"» (where Id is the
>identity function), but I agree this is a little inconvenient.
>

Or
	do
	 local f=function (x) print(x) end
	 f"hello"
	end

which is not convenient either, but perhaps is clearer.
--lhf

Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Reuben Thomas-3
In reply to this post by Roberto Ierusalimschy
On Tue, 30 Jan 2001, Roberto Ierusalimschy wrote:

> > You have to write plus(3), and then can't apply the result directly to 4
>
> You can, as long as you use the parentheses: plus(3)(4) is legal syntax.

Oh, goody. I got confused, because I tried writing:

(plus(3))(4)

and this seems to be illegal (which is a little counter-intuitive: adding
extra brackets shouldn't matter).

-- 
http://sc3d.org/rrt/ | humour, n.  unexpected recognition


Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Luiz Henrique de Figueiredo
In reply to this post by John Belmonte-2
>Oh, goody. I got confused, because I tried writing:
>
>(plus(3))(4)
>
>and this seems to be illegal (which is a little counter-intuitive: adding
>extra brackets shouldn't matter).

But expressions beginning with brackets introduce ambiguity:

	a=b
	(f)(2)

The code above is parsed as a=b(f)(2) not as a=b;(f)(2).
Some languages have a rule that newlines end statements if it makes sense to
do so, but isn't that confusing too? Plus I don't think it would be easy to
add this feature to the Lua parser.
--lhf

Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Nikos K Gorogiannis
Luiz Henrique de Figueiredo wrote:

[snip]
> But expressions beginning with brackets introduce ambiguity:
> 
>         a=b
>         (f)(2)
> 
> The code above is parsed as a=b(f)(2) not as a=b;(f)(2).
> Some languages have a rule that newlines end statements if it makes 
> sense to do so, but isn't that confusing too? Plus I don't think it 
> would be easy to add this feature to the Lua parser.

I may be stepping on language designers' toes here, but I always wanted
to ask this: (regardless of the functional programming examples), why
isn't it the case that a semicolon must always be present to end the
statement? I know that a change like this isn't feasible now, with all
the code that would be broken, but I just wanted to hear about the
rationale of this choice.

Cheers,
Nikos

Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Luiz Henrique de Figueiredo
In reply to this post by Luiz Henrique de Figueiredo
>why isn't it the case that a semicolon must always be present to end the
>statement?

Lua as designed to be used by non-programmers, or at least, not professional
programmers and we decided that semicolons would be a source of trouble.
For this audience, demanding semicolons to end statements would not make sense.

On the other hand, we ended up with a situation where semicolons are virtually
useless, because they cannot be used to remove ambiguities in code. The only
real use of semicolons is for readbility, as in "a=b  c=d", which reads better
when written "a=b;  c=d".
Unfortunately, it's not something that can be changed now.
--lhf

Reply | Threaded
Open this post in threaded view
|

Re: fun with table constructors

Reuben Thomas-3
In reply to this post by Luiz Henrique de Figueiredo
> But expressions beginning with brackets introduce ambiguity:
>
> 	a=b
> 	(f)(2)
>
> The code above is parsed as a=b(f)(2) not as a=b;(f)(2).

Ah.

> Some languages have a rule that newlines end statements if it makes sense to
> do so, but isn't that confusing too?

I use Lua as if it did, normally: I always put ; in when I have two
statements on the same line, and never when I have statements on different
lines. The difficult thing is that it must be possible to split a statement
across lines.

Haskell has a "layout rule" which uses white space for nesting. This seems
to work well most of the time: the amount of space at the start of a line
determines the nesting level, by comparison with previous lines which have
the same amount of white space.

Lua doesn't need the full glory of layout, because it has explicitly
delimited blocks (in Haskell, you either use braces *or* the layout rule).
A simple rule that could work for Lua might be:

  If a line starts with more white space than the previous one,
  treat it as a continuation; otherwise treat it as a new statement.

To count white space, expand tabs to some number of spaces, and then just
count the total number of spaces. Or to avoid the tab-counting problem,
declare it a syntax error if the shorter line's initial white space is not a
prefix of the longer line's initial white space.

But it's a great pity that you can't write and immediately apply anonymous
functions.

-- 
http://sc3d.org/rrt/ | Caution Children At Play Drive Slowly



Reply | Threaded
Open this post in threaded view
|

RE: fun with table constructors

Luiz Carlos de Castro Silveira Filho
In reply to this post by Luiz Henrique de Figueiredo
> 
> f 3  => f(3)
> 
> then we could write
> 
> function plus(a) return function (b) return %a + b end end
> 
> plus 3 4
> 
> ...but this is not legal syntax. You have to write plus(3), 
> and then can't
> apply the result directly to 4, so you need:
> 
> a = plus(3)
> a(4)
> 

You can do that by changing two sections of the code ('lparser.c'):

first is in function 'var_or_func', line 457: add the line
      case TK_NUMBER:

second, in function 'funcargs', line 412, add the lines
    case TK_NUMBER: {  /* funcargs -> NUMBER */
      Number r = ls->t.seminfo.r;
      next(ls);
      luaK_number(fs, r);
      break;
    }

to test, just a little change in your example:

function plus(a) return function (b) print (%a + b) end end
plus 3 4


I'm changing the parser and doing things similar to these.
I have a question to the Lua experts: do changes like these break the
grammar ?

Luiz.

Reply | Threaded
Open this post in threaded view
|

RE: fun with table constructors

Luiz Henrique de Figueiredo
In reply to this post by John Belmonte-2
>I'm changing the parser and doing things similar to these.
>I have a question to the Lua experts: do changes like these break the
>grammar ?

It's hard to say whether they break anything given that Lua's parser is a
hand-written recursive descent parser.
If you know what you're doing, you must check "follow" sets.

Also, please keep in mind that you have created a *different* language,
which cannot be called Lua, as explained in the FAQ.
(For a language to be called Lua it must have the same syntax and semantics
as "ours". Different libraries are ok.)
--lhf