Programming languages 如何用lambda演算术语定义匿名函数(或者我如何说某些语言支持匿名函数)?
java是否支持当前版本的6个lambda表达式或“匿名函数”?在java中有什么我做不到的,而在支持lambda表达式的编程语言中我做不到的?我知道java是图灵完备的,所以您可以在其中“做任何事情” 为什么匿名内部类包装函数不能表示lambda演算中定义的函数Programming languages 如何用lambda演算术语定义匿名函数(或者我如何说某些语言支持匿名函数)?,programming-languages,lambda,computer-science,Programming Languages,Lambda,Computer Science,java是否支持当前版本的6个lambda表达式或“匿名函数”?在java中有什么我做不到的,而在支持lambda表达式的编程语言中我做不到的?我知道java是图灵完备的,所以您可以在其中“做任何事情” 为什么匿名内部类包装函数不能表示lambda演算中定义的函数 什么是真正的匿名函数?您如何说某些语言支持匿名函数?C#中的lambda表达式和Java中的匿名内部类之间的一个重要区别是,内部类中引用的任何局部变量都由值捕获-这就是变量必须是最终变量的原因。该变量的值在构造时复制到内部类中 在C#
什么是真正的匿名函数?您如何说某些语言支持匿名函数?C#中的lambda表达式和Java中的匿名内部类之间的一个重要区别是,内部类中引用的任何局部变量都由值捕获-这就是变量必须是最终变量的原因。该变量的值在构造时复制到内部类中 在C#中,变量可以通过lambda表达式或方法中的其他代码进行更改,这些更改也可以在两个位置看到 您可以在Java中通过将原始变量包装在可变包装器中(例如,一个单元素数组)并使包装器变量成为最终变量来模拟这一点。这是一个相当糟糕的黑客 在IMO中使用匿名内部类的最大问题是过于冗长——声明要扩展的类,然后声明要重写的方法等等
有关闭包的更多信息,特别是在这方面比较Java和C,请参见。正如我在上面的评论中所暗示的,问题实际上取决于如何准确定义“支持”。在您的问题中,您已经提到Java是图灵完备的,因此Java“支持”(对于“支持”的某些定义)所有其他编程语言支持的东西 Java确实支持匿名函数:只需在Java中为λ演算编写一个解释器,并将匿名函数作为字符串传入即可 然而,我发现使用匿名函数需要做太多的工作。因此,对我来说,有趣的问题不是Java是否支持匿名函数,而是当我想使用匿名函数时,Java是否支持我。IOW:Java使匿名函数的使用变得容易了吗?它指导我吗?它帮助我吗 让我们做一个简单的实验:实现
map
函数,并使用它通过1
增加列表中的每个元素[1,2,3,4,5]
哈斯克尔
以下是Haskell中的morph
(我将调用该函数,以避免与现有的内置map
函数冲突)的实现方式:
morph _ [] = []
morph f (x:xs) = f x : morph f xs
就这些。简短而甜蜜:用任何东西变形空列表就是空列表,而用至少一个元素变形列表就是将变形函数应用于第一个元素,并将其与变形列表其余部分的结果连接起来
如您所见,编写一个接受函数作为参数的函数非常简单,非常轻量级
假设我们有一个列表l
:
l = [1, 2, 3, 4, 5]
我们现在可以这样调用变形:
morph (\x -> 1 + x) l
同样,将匿名函数传递给高阶函数非常简单,非常轻量级
它看起来几乎像λ-微积分。事实上,如果您使用Haskell IDE、具有Haskell模式的文本编辑器或Haskell pretty打印机,它将实际显示如下:
morph (λx → 1 + x) l
(int x) -> x + 1
(int x) -> x + 1
如果我们使用运算符部分,它会变得更容易,允许我们传递部分应用的运算符:
morph (1+) l
或者,我们可以传递预定义的succ
函数,该函数返回整数的后续值:
morph succ l
虽然这当然不是一个匿名函数,但它是一个命名函数
斯卡拉
在Scala中,它看起来非常相似。主要区别在于Scala的类型系统比Haskell的更复杂,因此需要更多的类型注释:
def morph[A, B](l: List[A])(f: A => B): List[B] = l match {
case Nil => Nil
case x :: xs => f(x) :: morph(xs)(f)
}
它仍然很轻。基本上,我们所要做的就是将f
参数声明为A=>B
类型(即从A
类型到B
类型的函数),这实际上是函数1[A,B]
的语法糖
现在我们只需要我们的列表:
val l = List(1, 2, 3, 4, 5)
(define l '(1 2 3 4 5))
List<Integer> l = Arrays.asList(1, 2, 3, 4, 5);
并对其进行变形:
morph(l) {_ + 1}
这再次利用了Scala的一些语法优势。在匿名函数中,可以省略参数列表;如果每个参数只使用一次,并且按照定义的顺序使用,则可以简单地将它们称为\uuuu
但即使是完整的形式也没有太重:
morph(l) {(e) => e + 1}
如果我经历了将morph
作为某个类的实例方法的麻烦,并根据Pimp-My-Library模式定义了从List
到该类的隐式转换,我甚至可以编写类似的代码
l morph {_ + 1}
计划
当然,Scheme对于匿名函数和高阶函数应该没有问题。这是变形:
(define (morph f l)
(if (null? l)
null
(cons
(f (first l))
(morph f (rest l)))))
morph(l, new Function1<Integer, Integer>() {
@Override public Integer apply(Integer n) {
return n + 1;
}
});
以下是我们的清单:
val l = List(1, 2, 3, 4, 5)
(define l '(1 2 3 4 5))
List<Integer> l = Arrays.asList(1, 2, 3, 4, 5);
以及我们的匿名函数用法:
(morph (lambda (e) (+ e 1)) '(1 2 3 4 5))
红宝石
调用它几乎和Scala一样轻量级
l.morph {|e| e + 1 }
通过获取对1
的+
方法的引用,我可以在某种程度上复制Haskell示例中的运算符部分:
l.morph(&1.method(:+))
Ruby还有一个预定义的整数succ
方法,我们可以使用Symbol#to_proc
技巧传递:
l.morph(&:succ)
有些人批评Ruby中的块,因为每个方法只能使用一个块,而使用多个函数的方法要难看得多,但实际上并没有那么糟糕。下面是与上面相同的代码,但不使用块:
module Enumerable
def morph(f)
[].tap &-> r { each &-> e { r << f.(e) }}
end
end
l = [1, 2, 3, 4, 5]
l.morph -> e { e + 1 }
l.morph(1.method(:+))
这里主要的干扰是通常丑陋的语法,而不是高阶函数的处理
让我们建立我们的列表(好的,数组):
并调用morph
函数(实际上,在本例中是一个方法),将匿名函数作为参数传递:
l.morph(function (e) { return e + 1; });
l.morph(e => e + 1);
interface Action1_T { void apply(T a); }
interface Action1_byte { void apply(byte a); }
interface Action1_short { void apply(short a); }
interface Action1_int { void apply(int a); }
interface Action1_long { void apply(long a); }
interface Action1_float { void apply(float a); }
interface Action1_double { void apply(double a); }
interface Action1_boolean { void apply(boolean a); }
interface Action1_char { void apply(char a); }
interface Function1_T_R { R apply(T a); }
interface Function1_T_byte { byte apply(T a); }
interface Function1_T_short { short apply(T a); }
interface Function1_T_int { int apply(T a); }
interface Function1_T_long { long apply(T a); }
interface Function1_T_float { float apply(T a); }
interface Function1_T_double { double apply(T a); }
interface Function1_T_boolean { boolean apply(T a); }
interface Function1_T_char { char apply(T a); }
interface Function1_byte_R { R apply(byte a); }
interface Function1_byte_byte { byte apply(byte a); }
interface Function1_byte_short { short apply(byte a); }
interface Function1_byte_int { int apply(byte a); }
interface Function1_byte_long { long apply(byte a); }
interface Function1_byte_float { float apply(byte a); }
interface Function1_byte_double { double apply(byte a); }
interface Function1_byte_boolean { boolean apply(byte a); }
interface Function1_byte_char { char apply(byte a); }
interface Function1_short_R { R apply(short a); }
interface Function1_short_byte { byte apply(short a); }
interface Function1_short_short { short apply(short a); }
interface Function1_short_int { int apply(short a); }
interface Function1_short_long { long apply(short a); }
interface Function1_short_float { float apply(short a); }
interface Function1_short_double { double apply(short a); }
interface Function1_short_boolean { boolean apply(short a); }
interface Function1_short_char { char apply(short a); }
interface Function1_int_R { R apply(int a); }
interface Function1_int_byte { byte apply(int a); }
interface Function1_int_short { short apply(int a); }
interface Function1_int_int { int apply(int a); }
interface Function1_int_long { long apply(int a); }
interface Function1_int_float { float apply(int a); }
interface Function1_int_double { double apply(int a); }
interface Function1_int_boolean { boolean apply(int a); }
interface Function1_int_char { char apply(int a); }
interface Function1_long_R { R apply(long a); }
interface Function1_long_byte { byte apply(long a); }
interface Function1_long_short { short apply(long a); }
interface Function1_long_int { int apply(long a); }
interface Function1_long_long { long apply(long a); }
interface Function1_long_float { float apply(long a); }
interface Function1_long_double { double apply(long a); }
interface Function1_long_boolean { boolean apply(long a); }
interface Function1_long_char { char apply(long a); }
interface Function1_float_R { R apply(float a); }
interface Function1_float_byte { byte apply(float a); }
interface Function1_float_short { short apply(float a); }
interface Function1_float_int { int apply(float a); }
interface Function1_float_long { long apply(float a); }
interface Function1_float_float { float apply(float a); }
interface Function1_float_double { double apply(float a); }
interface Function1_float_boolean { boolean apply(float a); }
interface Function1_float_char { char apply(float a); }
interface Function1_double_R { R apply(double a); }
interface Function1_double_byte { byte apply(double a); }
interface Function1_double_short { short apply(double a); }
interface Function1_double_int { int apply(double a); }
interface Function1_double_long { long apply(double a); }
interface Function1_double_float { float apply(double a); }
interface Function1_double_double { double apply(double a); }
interface Function1_double_boolean { boolean apply(double a); }
interface Function1_double_char { char apply(double a); }
interface Function1_boolean_R { R apply(boolean a); }
interface Function1_boolean_byte { byte apply(boolean a); }
interface Function1_boolean_short { short apply(boolean a); }
interface Function1_boolean_int { int apply(boolean a); }
interface Function1_boolean_long { long apply(boolean a); }
interface Function1_boolean_float { float apply(boolean a); }
interface Function1_boolean_double { double apply(boolean a); }
interface Function1_boolean_boolean { boolean apply(boolean a); }
interface Function1_boolean_char { char apply(boolean a); }
interface Function1_char_R { R apply(char a); }
interface Function1_char_byte { byte apply(char a); }
interface Function1_char_short { short apply(char a); }
interface Function1_char_int { int apply(char a); }
interface Function1_char_long { long apply(char a); }
interface Function1_char_float { float apply(char a); }
interface Function1_char_double { double apply(char a); }
interface Function1_char_boolean { boolean apply(char a); }
interface Function1_char_char { char apply(char a); }
ECMAScript(2015年后)
ECMAScript 2015引入了“fat”
l.Morph(e => e + 1);
l.Morph((e) => { return e + 1; });
static <A, B> List<B> morph(List<A> l, Function1<A, B> f) {
List<B> r = new ArrayList<>();
for (A e: l) r.add(f.apply(e));
return r;
}
List<Integer> l = Arrays.asList(1, 2, 3, 4, 5);
morph(l, new Function1<Integer, Integer>() {
@Override public Integer apply(Integer n) {
return n + 1;
}
});
morph(l, new Function1<Integer, Integer>() { @OVerride public Integer apply(Integer n) { return n + 1; }});
interface Function1<A, B> {
B apply(A a);
}
interface Action1_T { void apply(T a); }
interface Action1_byte { void apply(byte a); }
interface Action1_short { void apply(short a); }
interface Action1_int { void apply(int a); }
interface Action1_long { void apply(long a); }
interface Action1_float { void apply(float a); }
interface Action1_double { void apply(double a); }
interface Action1_boolean { void apply(boolean a); }
interface Action1_char { void apply(char a); }
interface Function1_T_R { R apply(T a); }
interface Function1_T_byte { byte apply(T a); }
interface Function1_T_short { short apply(T a); }
interface Function1_T_int { int apply(T a); }
interface Function1_T_long { long apply(T a); }
interface Function1_T_float { float apply(T a); }
interface Function1_T_double { double apply(T a); }
interface Function1_T_boolean { boolean apply(T a); }
interface Function1_T_char { char apply(T a); }
interface Function1_byte_R { R apply(byte a); }
interface Function1_byte_byte { byte apply(byte a); }
interface Function1_byte_short { short apply(byte a); }
interface Function1_byte_int { int apply(byte a); }
interface Function1_byte_long { long apply(byte a); }
interface Function1_byte_float { float apply(byte a); }
interface Function1_byte_double { double apply(byte a); }
interface Function1_byte_boolean { boolean apply(byte a); }
interface Function1_byte_char { char apply(byte a); }
interface Function1_short_R { R apply(short a); }
interface Function1_short_byte { byte apply(short a); }
interface Function1_short_short { short apply(short a); }
interface Function1_short_int { int apply(short a); }
interface Function1_short_long { long apply(short a); }
interface Function1_short_float { float apply(short a); }
interface Function1_short_double { double apply(short a); }
interface Function1_short_boolean { boolean apply(short a); }
interface Function1_short_char { char apply(short a); }
interface Function1_int_R { R apply(int a); }
interface Function1_int_byte { byte apply(int a); }
interface Function1_int_short { short apply(int a); }
interface Function1_int_int { int apply(int a); }
interface Function1_int_long { long apply(int a); }
interface Function1_int_float { float apply(int a); }
interface Function1_int_double { double apply(int a); }
interface Function1_int_boolean { boolean apply(int a); }
interface Function1_int_char { char apply(int a); }
interface Function1_long_R { R apply(long a); }
interface Function1_long_byte { byte apply(long a); }
interface Function1_long_short { short apply(long a); }
interface Function1_long_int { int apply(long a); }
interface Function1_long_long { long apply(long a); }
interface Function1_long_float { float apply(long a); }
interface Function1_long_double { double apply(long a); }
interface Function1_long_boolean { boolean apply(long a); }
interface Function1_long_char { char apply(long a); }
interface Function1_float_R { R apply(float a); }
interface Function1_float_byte { byte apply(float a); }
interface Function1_float_short { short apply(float a); }
interface Function1_float_int { int apply(float a); }
interface Function1_float_long { long apply(float a); }
interface Function1_float_float { float apply(float a); }
interface Function1_float_double { double apply(float a); }
interface Function1_float_boolean { boolean apply(float a); }
interface Function1_float_char { char apply(float a); }
interface Function1_double_R { R apply(double a); }
interface Function1_double_byte { byte apply(double a); }
interface Function1_double_short { short apply(double a); }
interface Function1_double_int { int apply(double a); }
interface Function1_double_long { long apply(double a); }
interface Function1_double_float { float apply(double a); }
interface Function1_double_double { double apply(double a); }
interface Function1_double_boolean { boolean apply(double a); }
interface Function1_double_char { char apply(double a); }
interface Function1_boolean_R { R apply(boolean a); }
interface Function1_boolean_byte { byte apply(boolean a); }
interface Function1_boolean_short { short apply(boolean a); }
interface Function1_boolean_int { int apply(boolean a); }
interface Function1_boolean_long { long apply(boolean a); }
interface Function1_boolean_float { float apply(boolean a); }
interface Function1_boolean_double { double apply(boolean a); }
interface Function1_boolean_boolean { boolean apply(boolean a); }
interface Function1_boolean_char { char apply(boolean a); }
interface Function1_char_R { R apply(char a); }
interface Function1_char_byte { byte apply(char a); }
interface Function1_char_short { short apply(char a); }
interface Function1_char_int { int apply(char a); }
interface Function1_char_long { long apply(char a); }
interface Function1_char_float { float apply(char a); }
interface Function1_char_double { double apply(char a); }
interface Function1_char_boolean { boolean apply(char a); }
interface Function1_char_char { char apply(char a); }
interface Function1_int_int {
int apply(int x)
}
(int x) -> x + 1
new Function1_int_int {
@Override public int apply(int x) {
return x + 1;
}
}
(int x) -> x + 1
interface * {
int *(int *)
}
class * {
int *(int *) // abstract!
}
static <A, B> List<B> morph(List<A> l, Function<A, B> f) {
List<B> r = new ArrayList<>();
for (var e: l) r.add(f.apply(e));
return r;
}
List<Integer> l = Arrays.asList(1, 2, 3, 4, 5);
morph(l, new Function<Integer, Integer>() {
@Override public Integer apply(Integer n) {
return n + 1;
}
});
morph(l, n -> n + 1);