2 oklu lambda Java 8'de ne anlama geliyor?


118

Daha önce birkaç Java 8 öğreticisi okudum.

Şu anda şu konuyla karşılaştım: Java, Currying'i destekliyor mu?

Burada aşağıdaki kodu görüyorum:

IntFunction<IntUnaryOperator> curriedAdd = a -> b -> a + b;
System.out.println(curriedAdd.apply(1).applyAsInt(12));

Bu örneğin 2 elementi topladığını anlıyorum ama yapıyı anlayamıyorum:

a -> b -> a + b;

İfadenin sol kısmına göre, bu satır aşağıdaki işlevi uygulamalıdır:

R apply(int value); 

Bundan önce, lambdalarla sadece bir okla tanıştım.


6
Köri ne demek anlıyor musun? Bu, bu sorunun oldukça ayrılmaz bir parçasıdır.
BlueRaja - Dany Pflughoeft

12
Bu sadece bir lambda döndüren bir lambda.
Ilmari Karonen

Yanıtlar:


118

Bunu kısaltılmamış lambda sözdizimi veya pre-lambda Java anonim sınıf sözdizimi olarak ifade ederseniz, ne olduğu daha açıktır ...

Asıl soru. Neden iki ok var? Basit, tanımlanmakta olan iki işlev vardır ... İlk işlev bir işlevi tanımlayan işlevdir, ikincisi de işlev olan bu işlevin sonucudur. Her biri bir ->operatörün tanımlamasını gerektirir .

Sigara steno

IntFunction<IntUnaryOperator> curriedAdd = (a) -> {
    return (b) -> {
        return a + b;
    };
};

Java 8'den önce Lambda öncesi

IntFunction<IntUnaryOperator> curriedAdd = new IntFunction<IntUnaryOperator>() {
    @Override
    public IntUnaryOperator apply(final int value) {
        IntUnaryOperator op = new IntUnaryOperator() {
            @Override
            public int applyAsInt(int operand) {
                return operand + value;
            }
        };
        return op;
    }
};

1
pre-lambda için afinal int value
njzk2

8
Evet, haklısınız, ancak yine de "etkili bir şekilde nihai" olan şeyleri kullanmanıza izin veren bir Java 8 derleyicisi kullandığınızı yazdım
Adam

1
@gstackoverflow evet, ama o zaman java 8 değilpre-lambda
njzk2

1
pre-lambda stilini java 8'de de kullanabilirsiniz. Ben yazdım JFY
gstackoverflow

3
Lambdalar sadece insanların puan alabilmesi için yapılmamış mıydı? :-)
Stephane

48

An IntFunction<R>bir işlevdir int -> R. An IntUnaryOperatorbir işlevdir int -> int.

Bu nedenle, bir IntFunction<IntUnaryOperator>bir alan bir fonksiyonu olan intparametre olarak bir alan bir geri dönüş fonksiyonu intparametre olarak bir dönüş int.

a -> b -> a + b;
^    |         |
|     ---------
|         ^
|         |
|         The IntUnaryOperator (that takes an int, b) and return an int (the sum of a and b)
|
The parameter you give to the IntFunction

Lambda'yı "ayrıştırmak" için anonim sınıfları kullanırsanız belki daha açık:

IntFunction<IntUnaryOperator> add = new IntFunction<IntUnaryOperator>() {
    @Override
    public IntUnaryOperator apply(int a) {
        return new IntUnaryOperator() {
            @Override
            public int applyAsInt(int b) {
                return a + b;
            }
        };
    }
};

29

Parantez eklemek bunu daha açık hale getirebilir:

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

Ya da muhtemelen ara değişken yardımcı olabilir:

IntFunction<IntUnaryOperator> curriedAdd = a -> {
    IntUnaryOperator op = b -> a + b;
    return op;
};

24

Lambda ifadesini daha açık hale getirmek için parantezlerle yeniden yazalım:

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

Böylece, a intdöndüren an alan bir fonksiyon bildiriyoruz Function. Daha spesifik olarak, döndürülen işlev an alır intve bir int(iki öğenin toplamı) döndürür : bu, bir IntUnaryOperator.

Bu nedenle, curriedAddbir alan intve dönen bir fonksiyondur IntUnaryOperator, bu yüzden olarak temsil edilebilir IntFunction<IntUnaryOperator>.


9

Bu iki lambda ifadesi.

IntFunction<IntUnaryOperator> curriedAdd = 
  a -> { //this is for the fixed value
    return b -> { //this is for the add operation
      return a + b;
    };
  }

IntUnaryOperator addTwo = curriedAdd.apply(2);
System.out.println(addTwo.applyAsInt(12)); //prints 14

8

Eğer bakarsanız IntFunctiondaha net hale gelebilir: IntFunction<R>is a FunctionalInterface. Bir alan intve bir tür değeri döndüren bir işlevi temsil eder R.

Bu durumda, dönüş türü Rde a FunctionalInterface, yani bir IntUnaryOperator. Dolayısıyla, birinci (dış) işlevin kendisi bir işlev döndürür.

Bu durumda: Bir uygulandığında int, curriedAddyine bir götüren bir işlev döndürecek gerekiyordu int(tekrar döner into en neyi çünkü IntUnaryOperatoryapar).

Fonksiyonel programlamada bir fonksiyonun tipini olarak yazmak yaygındır param -> return_valueve burada tam olarak bunu görürsünüz. Tipi Yani curriedAddolduğunu int -> int -> int(ya da int -> (int -> int)daha iyi gibi ise).

Java 8'in lambda sözdizimi bununla birlikte gider. Böyle bir işlevi tanımlamak için yazarsınız

a -> b -> a + b

gerçek lambda hesabına çok benzer:

λa λb a + b

λb a + btek bir parametre alan bve bir değer (toplam) döndüren bir işlevdir . λa λb a + btek bir parametreyi kabul eden ave tek bir parametrenin başka bir fonksiyonunu döndüren bir fonksiyondur. λa λb a + bdöner λb a + bile aparametre değerine set.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.