Skip to content

Commit

Permalink
Add self() for anonymous function recursion (#83)
Browse files Browse the repository at this point in the history
* Add self() for anonymous function recursion

* use self() in a couple of examples, add a todo

* update readme a bit

* update readme example
  • Loading branch information
ldemailly authored Aug 1, 2024
1 parent aa14201 commit e012b22
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 18 deletions.
23 changes: 15 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,37 @@ Or get one of the [binary releases](https://github.com/grol-io/grol/releases)
## What it does
Sample:
```go
gorepl -parse
$ fact = func(n) {if (n<=1) {return 1} n*fact(n-1)}
$ grol -parse
10:53:12.675 grol 0.29.0 go1.22.5 arm64 darwin - welcome!
$ fact = func(n) {if (n<=1) {return 1} n*self(n-1)} // could be n*fact(n-1) too
== Parse ==> fact = func(n) {
if n <= 1 {
return 1
}
n * self(n - 1)
}
$ n=fact(6)
== Parse ==> (n = fact(6))
== Parse ==> n = fact(6)
== Eval ==> 720
$ m=fact(7)
== Parse ==> (m = fact(7))
== Parse ==> m = fact(7)
== Eval ==> 5040
$ m/n
== Parse ==> (m / n)
== Parse ==> m / n
== Eval ==> 7
```

## Language features

Functional int, float, string and boolean expressions

Functions, lambdas, closures
Functions, lambdas, closures (including recursion in anonymous functions, using `self()`)

Arrays, maps,
Arrays, maps

print, log

macros and more all the time
macros and more all the time (like canonical reformat using `grol -format` and wasm/online version etc)

See also [sample.gr](examples/sample.gr) and others in that folder, that you can run with
```
Expand Down
4 changes: 3 additions & 1 deletion eval/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,9 @@ func extendFunctionEnv(name string, fn object.Function, args []object.Object) (*
for paramIdx, param := range fn.Parameters {
env.Set(param.Value().Literal(), args[paramIdx])
}

// for recursion in anonymous functions.
// TODO: consider not having to keep setting this in the function's env and treating as a keyword.
env.Set("self", fn)
return env, nil
}

Expand Down
8 changes: 8 additions & 0 deletions eval/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ func TestEvalIntegerExpression(t *testing.T) {
{`a=2; b=3; r=a+5*(b++)+b;`, 21}, // left to right eval, yet not that not well defined behavior.
{`a=2; b=3; r=b+5*(b++)+a;`, 20}, // because that solo b is evaluated last, after the b++ - not well defined behavior.
{`a=2; b=3; r=a+5*b+++b;`, 21}, // parentheses are not technically needed here though... this is rather un readable.
{`// IIFE factorial
func(n) {
if n <= 1 {
return 1
}
n * self(n - 1)
}(5)
`, 120},
}

for i, tt := range tests {
Expand Down
11 changes: 11 additions & 0 deletions examples/anon.gr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
Anonymous function recursion
Define and immediately call factorial
(IIFE: Immediately Invoked Function Expression)
*/
func(n) {
if n <= 1 {
return 1
}
n * self(n - 1)
}(5) // will return 120
16 changes: 8 additions & 8 deletions examples/pi2.gr
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
Γ(x + 1/2) ~ Γ(x)x^(1/2) = (x-1)!√x
Γ(x + 1/2) = (2x - 1)!! * 2^-x * √π
*/
f=func(i,n, prod) {
//log(i, prod)
if (i==n+1) {
return 1./(prod*prod*n)
}
f(i+1, n, prod * ( 1 - 1./(2*i)))
f = func(i, n, prod) {
//log(i, prod)
if i == n+1 {
return 1. / (prod * prod * n)
}
self(i+1, n, prod*(1-1./(2*i)))
}
n=200000
f(1,n,1)
n = 200000
f(1, n, 1)
2 changes: 1 addition & 1 deletion examples/sample.gr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fact=func(n) { // function
if (n<=1) {
return 1
}
/* recursion: */ n*fact(n-1) // also last evaluated expression is returned (ie return at the end is optional)
/* recursion: */ n*self(n-1) // also last evaluated expression is returned (ie return at the end is optional)
}

a=[fact(5), "abc", 76-3] // array can contain different types
Expand Down

0 comments on commit e012b22

Please sign in to comment.