How to refer a Lambda?
Asked Answered
R

3

3

How can I refer a Lambda from inside of it, if, for example, I need to use myLambda recursively?

myLambda -> {expression}
//           ^^^^^^^^^^ how can I refer to myLambda here?
Rolypoly answered 4/1, 2015 at 16:40 Comment(5)
That's a very backwards way to understand a question.Falito
@Abdellah (1) I also wouldn't care much if 10% wouldn't understand my question, but problem is that your question can't be clearly understood by much more than 10% of us and we on Stack Overflow are trying to create library of hight quality question-answers, so question and answers need to be as clear as possible. (2) "like we reference a class with this" this doesn't refer class, but instance of class.Elurd
@Elurd feel free to correct me if I am wrong. I like to learn from my mistakes :)Rolypoly
I tried to change your question into something clearer, but I am not sure if I didn't change it too much. Feel free to rollback my edit if it is incorrect.Elurd
It was a deliberate design decision to not support this. As some of the other answers suggest, there are tricks with mutable fields (where lambdas can refer to fields that are uninitialized at time of capture but defined at time of invocation), but these have sharp edges. The key decision was: with the exception of lambda formals, names have the same meaning inside a lambda as they do outside of it, including this. This is a major simplification over inner classes, whose name-lookup rules are highly complex and error-prone.Goldsberry
D
4

I misunderstood your question. Here's how you call a lambda expression recursively :

import java.util.function.*;
public class Test
{
    static Function<Integer, Integer> fib = null;

    public static void main (String[] args)
    {      
        fib = n ->
              n == 0 ? 0
              : n == 1 ? 1
              : fib.apply(n - 1) + fib.apply(n - 2); 
        System.out.println(fib.apply(8));
    }

}

This produces the output 21.

I borrowed the example from Jon Skeet and made the changes required to make it work.

You can find another example of a recursive lambda expression here.

Desmarais answered 4/1, 2015 at 16:43 Comment(3)
I don't think that's what the OP wants - I think he wants to be able to refer to the lambda expression value within it.Othilie
To be honest, I have some troubles to understand how this does not produce a NPE. As I understand it, fib.apply(8) will try to call fib.apply(7) + fib.apply(6); but at that time fib is still null right? So why don't you get a NPE?Concernment
@Desmarais Since you didn't answer, I asked the question here FYI: #27770308Concernment
O
7

If you mean you want to refer to the lambda expression you're defining within that lambda expression, I don't believe there's any such mechanism. I know of a few cases where it would be useful - recursive definitions, basically - but I don't believe it's supported.

The fact that you can't capture non-final variables in Java makes this even harder. For example:

// This doesn't compile because fib might not be initialized
Function<Integer, Integer> fib = n ->
      n == 0 ? 0
      : n == 1 ? 1
      : fib.apply(n - 1) + fib.apply(n - 2);

And:

// This doesn't compile because fib is non-final
Function<Integer, Integer> fib = null;
fib = n ->
      n == 0 ? 0
      : n == 1 ? 1
      : fib.apply(n - 1) + fib.apply(n - 2);

A Y-combinator would help here, but I don't have the energy to come up with an example in Java right now :(

Othilie answered 4/1, 2015 at 16:47 Comment(7)
This is why people write Y combinators.Thisbe
@SLaks: Indeed. Have tried to get that working, and run into Sunday afternoon malaise :)Othilie
Maybe to help you with your example: rosettacode.org/wiki/Y_combinator#JavaFalito
You can make your second snippet work by making fib a static variable.Desmarais
@Eran: True - but that's nasty in other ways, IMO. For example, it means you can't capture a local variable passed into a method (without risking collisions).Othilie
@JonSkeet, can you please elaborate on your statement about collisions?Amorino
@Vic: If you have multiple threads which end up assigning to the same variable, but each refer to that variable expecting "their" lambda, you could get into trouble really easily.Othilie
D
4

I misunderstood your question. Here's how you call a lambda expression recursively :

import java.util.function.*;
public class Test
{
    static Function<Integer, Integer> fib = null;

    public static void main (String[] args)
    {      
        fib = n ->
              n == 0 ? 0
              : n == 1 ? 1
              : fib.apply(n - 1) + fib.apply(n - 2); 
        System.out.println(fib.apply(8));
    }

}

This produces the output 21.

I borrowed the example from Jon Skeet and made the changes required to make it work.

You can find another example of a recursive lambda expression here.

Desmarais answered 4/1, 2015 at 16:43 Comment(3)
I don't think that's what the OP wants - I think he wants to be able to refer to the lambda expression value within it.Othilie
To be honest, I have some troubles to understand how this does not produce a NPE. As I understand it, fib.apply(8) will try to call fib.apply(7) + fib.apply(6); but at that time fib is still null right? So why don't you get a NPE?Concernment
@Desmarais Since you didn't answer, I asked the question here FYI: #27770308Concernment
A
1

If you want to define a recursive function, use Java’s canonical way to implement a recursive function: a method:

public static int fib(int n) {
    return n==0? 0: n==1? 1: fib(n-1)+fib(n-2);
}

Then, if you need a instance fulfilling a functional interface you can use a method reference:

Function<Integer, Integer> fib = MyClass::fib;

or

IntUnaryOperator fib0=MyClass::fib;
Angarsk answered 5/1, 2015 at 9:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.