Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lambda support #82

Open
srackham opened this issue Aug 27, 2022 · 7 comments
Open

Lambda support #82

srackham opened this issue Aug 27, 2022 · 7 comments

Comments

@srackham
Copy link
Contributor

srackham commented Aug 27, 2022

Virgil doesn't currently support lambdas, but support will be added soon.

I guess this means anonymous functions with closures?

For example:

def intSeq() -> () -> int {
    var i = 0;
    return () -> int {
        i = i + 1;
        return i;
    }
}
@titzer
Copy link
Owner

titzer commented Aug 27, 2022

Yeah. Internally I decided to call the feature funcexpr (function expressions) and the AST node FuncExpr.

I added a bunch of tests to test/funcexpr and I added parser support, but I disabled that on purpose until I do a stable revision (i.e. check in the results of aeneas bootstrap as the next stable binary), because I don't want stable to support incomplete features.

Personally I kind of like the fat arrow => from JavaScript lambda syntax. I went down that route but it requires backtracking to reinterpret expressions when the => is hit. I wrestled with some alternative syntaxes before eventually just settling on using the def keyword to introduce a function expression.

//@execute = 112
def main() -> int {
	return (def () => 112)();
}

I'd like to further expand the => operator to allow it to denote that a method has a body that consists of a single expression and its return type is implicitly that expression's type.

@execute 33=33
class C(val: int) {
  def inc() => val++;
}
def main(a: int) => C.new(a).inc();

@srackham
Copy link
Contributor Author

What is the reason for a separate lambda syntax, why not just have anonymous nested methods? This is the route taken by Go, it's more general and there's one less concept e.g. https://gobyexample.com/closures

@titzer
Copy link
Owner

titzer commented Aug 27, 2022

Actually I think what I am proposing is really close to what Go does.

The fat arrow => is just a shorthand that is actually independent of whether you're declaring a method or creating a closure with an anonymous function (function expression).

E.g. a method:

def foo() => 0;
// is equivalent to:
def foo() -> int {
  return 0;
}

And a function expression:

var x = def() => 0;
// is equivalent to:
var x = def() -> int { return 0; }

Have a look at some of the examples in test/funcexpr, I think it will be clearer.

@srackham
Copy link
Contributor Author

Have a look at some of the examples in test/funcexpr, I think it will be clearer.

Much clearer, thanks.

The test examples are all single-statement anonymous functions. Are multi-statement anonymous functions allowed? For example is this closure over a multi-statement anonymous function valid?

def intSeq() -> def() -> int {
    var i = 0;
    return def() -> int {
        i = i + 1;
        return i;
    }
}

@titzer
Copy link
Owner

titzer commented Aug 28, 2022

Yes, that would be valid (in terms of syntax[1]), though I think I want to disallow closing over mutable locals and only allow closing over def locals, loop variables, and assigned-once variables.

[1] with a minor correction in the return type:

def intSeq() -> () -> int {
    var i = 0;
    return def() -> int {
        i = i + 1;
        return i;
    }
}

Java also doesn't allow closing over mutable locals. So you could, e.g. use an array.

def intSeq() -> () -> int {
    def v = [0];
    return def() -> int {
        return v[0]++;
    }
}
// or, shorter
def intSeq() -> () -> int {
    def v = [0];
    return def() => v[0]++;
}

@diakopter
Copy link
Contributor

as long as they allow closing over something in outer scopes, Virgil would be able to idiomatically express Knuth's so-called "Man or Boy test" as depicted here for other programming languages - https://rosettacode.org/wiki/Man_or_boy_test

(idiomatically, as opposed to simulating such lambda-closures with classes)

@titzer
Copy link
Owner

titzer commented Aug 30, 2022

Yes, the idea is that you can indeed close over immutable variables in function scopes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants