在阅读各种关于函数式编程的文章时,我遇到过几次“Functor”这个术语,但作者通常认为读者已经理解了这个术语。在网络上你可以看到一些过于技术性的描述(参见维基百科的文章),也可以看到一些非常模糊的描述(参见ocaml-tutorial网站上关于函数函数的部分)。
有没有人可以定义这个术语,解释它的用法,或者提供一个如何创建和使用函子的例子?
编辑:虽然我对这个术语背后的理论很感兴趣,但我对这个概念的实现和实际应用更感兴趣,而不是理论。
编辑2:看起来好像有一些交叉术语:我特别指的是函数式编程的函子,而不是c++的函数对象。
不是为了与前面的理论或数学答案相矛盾,但Functor也是一个对象(在面向对象编程语言中),它只有一个方法,并且可以有效地用作函数。
Java中的Runnable接口就是一个例子,它只有一个方法:run。
考虑这个例子,首先在Javascript中,它有一级函数:
[1, 2, 5, 10].map(function(x) { return x*x; });
输出:
[1,4,25,100]
map方法接受一个函数并返回一个新数组,其中每个元素都是将该函数应用于原始数组中相同位置的值的结果。
要在Java中使用Functor做同样的事情,你首先需要定义一个接口,比如:
public interface IntMapFunction {
public int f(int x);
}
然后,如果你添加一个集合类,它有一个映射函数,你可以这样做:
myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } });
这使用了IntMapFunction的一个内嵌子类来创建一个Functor,它是前面JavaScript示例中的函数的OO等效。
使用函子可以在OO语言中应用函数式技术。当然,一些OO语言也直接支持函数,所以这不是必需的。
参考:http://en.wikipedia.org/wiki/Function_object
在函数式编程中,错误处理是不同的。抛出和捕获异常是命令式代码。不是使用try/catch块,而是围绕可能抛出错误的代码创建一个安全框。这是函数式编程中的基本设计模式。包装器对象用于封装可能错误的值。包装器的主要目的是提供一种使用被包装对象的“不同”方式
const wrap = (val) => new Wrapper(val);
包装可以保护对值的直接访问,以便对它们进行操作
安全而不可改变。因为我们不能直接得到它,所以提取它的唯一方法就是使用恒等函数。
identity :: (a) -> a
这是恒等函数的另一个用例:从封装的类型中功能地提取数据。
Wrapper类型使用映射来安全地访问和操作值。在本例中,我们将恒等函数映射到容器上,以从容器中提取值。使用这种方法,可以在调用函数之前检查是否为null,或者检查是否为空字符串、负数等等。
fmap :: (A -> B) -> Wrapper[A] -> Wrapper[B]
Fmap,首先打开容器,然后将给定函数应用于它的值,最后将值关闭到相同类型的新容器中。这种类型的函数称为函子。
Fmap在每次调用时返回容器的新副本。
函子没有副作用
函子必须是可组合的
不是为了与前面的理论或数学答案相矛盾,但Functor也是一个对象(在面向对象编程语言中),它只有一个方法,并且可以有效地用作函数。
Java中的Runnable接口就是一个例子,它只有一个方法:run。
考虑这个例子,首先在Javascript中,它有一级函数:
[1, 2, 5, 10].map(function(x) { return x*x; });
输出:
[1,4,25,100]
map方法接受一个函数并返回一个新数组,其中每个元素都是将该函数应用于原始数组中相同位置的值的结果。
要在Java中使用Functor做同样的事情,你首先需要定义一个接口,比如:
public interface IntMapFunction {
public int f(int x);
}
然后,如果你添加一个集合类,它有一个映射函数,你可以这样做:
myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } });
这使用了IntMapFunction的一个内嵌子类来创建一个Functor,它是前面JavaScript示例中的函数的OO等效。
使用函子可以在OO语言中应用函数式技术。当然,一些OO语言也直接支持函数,所以这不是必需的。
参考:http://en.wikipedia.org/wiki/Function_object