Lambda abstraction

Wang Renxin edited this page Nov 20, 2017 · 17 revisions

Why and how

A lambda abstraction (aka. anonymous function or function literal) is a function definition that is not bound to an identifier. Lambda functions are often:

  1. Arguments being passed to higher order functions, or
  2. Used for constructing the result of a higher order function that needs to return a function

A lambda becomes a closure after it captured some values in outer scope.

MY-BASIC offers full support for lambda, including invokable as a value, higher order function, closure and currying, etc.

The syntax of lambda in MY-BASIC is:

    LAMBDA ::= lambda "(" PARAMETERS ")" "(" BODY ")"
PARAMETERS ::= variable { "," PARAMETERS }
      BODY ::= STATEMENTS
STATEMENTS ::= statement \n STATEMENTS

It begins with a LAMBDA keyword, and follows by a parameter list (with none or multiple parameter identifiers), then the lambda body. It's possible to write multiple line statements in a lambda body, use the RETURN statement to return a value from a lambda body.

Short identifier

The LAMBDA keyword is too long to type? Then try defining another short alias name for it by adding an MB_LAMBDA_ALIAS macro. For instance defining it with a single character ~, then ~ () () will be equivalent to lambda () ().

#ifndef MB_LAMBDA_ALIAS
#	define MB_LAMBDA_ALIAS "~"
#endif /* MB_LAMBDA_ALIAS */

Or even unicode alias.

#ifndef MB_LAMBDA_ALIAS
#	define MB_LAMBDA_ALIAS "\xce\xbb"
#endif /* MB_LAMBDA_ALIAS */

The hex symbol represents for the λ symbol.

l = λ (a, b) (return a + b)
print l(1, 2);

"Hold on. Where's a λ key?" Well, I hope there was one :)

Samples

Let's have a look at some short samples as follow.

Simple invoke:

f = lambda (x, y) (return x * x + y * y)
print f(3, 4);

Returning as a value:

def counter()
	c = 0

	return lambda (n)
	(
		c = c + n
		print c;
	)
enddef

acc = counter()

acc(1)
acc(2)

Higher order function:

def foo()
	y = 1

	return lambda (x, z) (return x + y + z)
enddef

l = foo()

print l(2, 3);

Closure:

s = 0

def create_lambda()
	v = 0

	return lambda ()
	(
		v = v + 1
		s = s + 1
		print v;
		print s;
	)
enddef

a = create_lambda()
b = create_lambda()

a()
b()

Currying:

def divide(x, y)
	return x / y
enddef

def divisor(d)
	return lambda (x) (return divide(x, d))
enddef

half = divisor(2)
third = divisor(3)

print half(32); third(32);

Folding:

def fold(lst, func, seed)
	r = seed
	l = clone(lst)
	while len(l) <> 0
		r = func(r, l(0))
		remove(l, 0)
	wend

	return r
enddef

lst = list(2, 3, 4)
func = lambda (l, r) (return l + r)
ret = fold(lst, func, 0)
print ret;

Lazy evaluation:

def fib(n)
	t0 = 0
	t1 = 0
	i = 0

	return lambda ()
	(
		if i = 0 then
			t = 1
		else
			t = t0 + t1
		endif
		t0 = t1
		t1 = t
		i = i + 1
		if i > n then
			return 0
		endif

		return t
	)
enddef

f = fib(20)
do
	n = f()
	if n then
		print n;
	endif
until not n

It's neat to implement a foreach loop with lambda:

def foreach(c, f)
	it = iterator(c)
	while move_next(it)
		item = get(it)
		f(item)
	wend
enddef

f = lambda (i) (print i;)

l = list(1, 2, 3, 4)

foreach(l, f)

It's also possible to implement a list iterator in another way by using a lambda to memorize states:

class my_list
	var l = list()

	var tail = "__TAIL__"

	def push_back(i)
		push(l, i)
	enddef

	def pop_back()
		return pop(l)
	enddef

	def get_iterator()
		it = iterator(l)

		return lambda ()
		(
			if not move_next(it) then
				return tail
			endif

			return get(it)
		)
	enddef
endclass

lst = new(my_list)
lst.push_back(1)
lst.push_back(2)
lst.push_back(3)
lst.push_back(4)

iter = lst.get_iterator()
do
	item = iter()
	if item <> lst.tail then
		print item;
	endif
until item = lst.tail
Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.