代码之家  ›  专栏  ›  技术社区  ›  Erik Forbes

在函数编程中,什么是函数?

  •  206
  • Erik Forbes  · 技术社区  · 15 年前

    在阅读有关函数编程的各种文章时,我遇到过“functor”这个词几次,但作者通常假定读者已经理解了这个词。在网络上四处查看提供了过度的技术描述(请参见 Wikipedia article )或者非常模糊的描述(参见下面关于函数的部分 ocaml-tutorial website )

    有人能很好地定义这个术语,解释它的用法,或者提供一个如何创建和使用函数的例子吗?

    编辑 :虽然我对该术语背后的理论感兴趣,但我对该理论的兴趣不如对该概念的实施和实际应用感兴趣。

    编辑2 看起来有一些交叉终端:我特别指的是函数编程的函数,而不是C++的函数对象。

    17 回复  |  直到 6 年前
        1
  •  259
  •   Norman Ramsey    14 年前

    “函子”一词来源于范畴理论,它是数学中一个非常普遍、非常抽象的分支。功能语言的设计者至少以两种不同的方式借用了它。

    • 在ML语言家族中,函数是以一个或多个其他模块为参数的模块。它被认为是一个高级特性,大多数初学者都很难使用它。

      作为实现和实际使用的一个例子,您可以一次性地将您最喜欢的平衡二进制搜索树定义为一个函数,它将作为一个参数,一个模块提供:

      • 要在二进制树中使用的键的类型

      • 键的总排序函数

      一旦完成了这项工作,就可以永远使用相同的平衡二叉树实现。(存储在树中的值的类型通常是多态的。树不需要查看值,而不需要复制它们,而树肯定需要能够比较键,并从函数的参数中获取比较函数。)

      ML函子的另一个应用是 layered network protocols . 这个链接是由CMUFox小组撰写的一篇非常棒的论文;它展示了如何使用函数在简单的层(如IP,甚至直接通过以太网)类型上构建更复杂的协议层(如TCP)。每一层都被实现为一个函数,将其下面的层作为参数。软件的结构实际上反映了人们对问题的思考方式,而不是那些只存在于程序员头脑中的层。1994年,当这部作品出版时,这是一件大事。

      对于一个实际使用的ml函数的示例,您可以看到这篇文章 ML Module Mania 其中包含一个可发布(即可怕)的函数示例。要获得对ML模块系统的精彩、清晰、清晰的解释(与其他类型的模块进行比较),请阅读Xavier Leroy's Brilliant 1994 Popl论文的前几页。 Manifest Types, Modules, and Separate Compilation .

    • 在haskell和一些相关的纯功能语言中, Functor 是一个 类型类 . 当类型提供具有特定预期行为的某些操作时,类型属于类型类(或者更严格地说,类型“是”类型类的实例)。一种 T 可以属于类 函子 如果它具有某些类似集合的行为:

      • 类型 T 在另一个类型上参数化,应将该类型视为集合的元素类型。完整集合的类型如下 T Int ,请 T String , T Bool ,如果分别包含整数、字符串或布尔值。如果元素类型未知,则将其写为 类型参数 a ,如 T a .

        示例包括列表(零个或多个类型的元素 ) Maybe 类型(零个或一个类型的元素 )类型的元素集 ,类型的元素数组 ,包含类型值的各种搜索树 还有很多你能想到的人。

      • 其他财产 T 必须满足的是,如果您具有类型的函数 a -> b (元素上的函数),然后您必须能够获取该函数并在集合上生成相关的函数。你和接线员一起做这个 fmap ,由中的每个类型共享 函数 类型类。运算符实际上是重载的,因此如果您有一个函数 even 带类型 Int -> Bool 然后

        fmap even
        

        是一个超负荷的函数,可以做很多奇妙的事情:

        • 将整数列表转换为布尔值列表

        • 将整数树转换为布尔树

        • 转换 Nothing 没有什么 Just 7 Just False

        在haskell中,此属性通过给出 FMAP :

        fmap :: (Functor t) => (a -> b) -> t a -> t b
        

        我们现在有一个小 t ,意思是“任何类型的 函数 “上课。”

      长话短说,哈斯克尔 函子是一种集合,如果在元素上给你一个函数, 格式管理 将返回集合的函数 . 正如您所能想象的,这是一个可以被广泛重用的想法,这就是为什么它作为Haskell标准库的一部分受到祝福的原因。

    像往常一样,人们继续发明新的、有用的抽象概念,你可能想研究一下 应用的 函数,其中最好的参考可能是一篇叫做 Applicative Programming with Effects 作者:康纳·麦克布莱德和罗斯·帕特森。

        2
  •  57
  •   nbro kai    7 年前

    这里的其他答案都是完整的,但我将尝试另一种解释 函子 . 以此为类比:

    函数是类型为的容器 当服从一个映射自 艾斯 ,生成类型为的容器 .

    与C++中使用的抽象函数指针不同,这里的函子是 函数;相反,当 服从某种功能 .

        3
  •  35
  •   sdcvvc    14 年前

    有三种不同的含义,没有太多的关联!

    • 在OCAML中,它是一个参数化模块。见 manual . 我认为摸索它们的最好方法是举个例子:(写得很快,可能有问题)

      module type Order = sig
          type t
          val compare: t -> t -> bool
      end;;
      
      
      module Integers = struct
          type t = int
          let compare x y = x > y
      end;;
      
      module ReverseOrder = functor (X: Order) -> struct
          type t = X.t
          let compare x y = X.compare y x
      end;;
      
      (* We can order reversely *)
      module K = ReverseOrder (Integers);;
      Integers.compare 3 4;;   (* this is false *)
      K.compare 3 4;;          (* this is true *)
      
      module LexicographicOrder = functor (X: Order) -> 
        functor (Y: Order) -> struct
          type t = X.t * Y.t
          let compare (a,b) (c,d) = if X.compare a c then true
                               else if X.compare c a then false
                               else Y.compare b d
      end;;
      
      (* compare lexicographically *)
      module X = LexicographicOrder (Integers) (Integers);;
      X.compare (2,3) (4,5);;
      
      module LinearSearch = functor (X: Order) -> struct
          type t = X.t array
          let find x k = 0 (* some boring code *)
      end;;
      
      module BinarySearch = functor (X: Order) -> struct
          type t = X.t array
          let find x k = 0 (* some boring code *)
      end;;
      
      (* linear search over arrays of integers *)
      module LS = LinearSearch (Integers);;
      LS.find [|1;2;3] 2;;
      (* binary search over arrays of pairs of integers, 
         sorted lexicographically *)
      module BS = BinarySearch (LexicographicOrder (Integers) (Integers));;
      BS.find [|(2,3);(4,5)|] (2,3);;
      

    现在,您可以快速添加许多可能的订单、形成新订单的方法、轻松地对它们执行二进制或线性搜索。通用编程FTW。

    • 在像Haskell这样的函数式编程语言中,它意味着一些可以“映射”的类型构造函数(参数化类型,如列表、集合)。准确地说,函数 f 配备 (a -> b) -> (f a -> f b) . 这起源于范畴理论。你链接到的维基百科文章就是这个用法。

      class Functor f where
          fmap :: (a -> b) -> (f a -> f b)
      
      instance Functor [] where      -- lists are a functor
          fmap = map
      
      instance Functor Maybe where   -- Maybe is option in Haskell
          fmap f (Just x) = Just (f x)
          fmap f Nothing = Nothing
      
      fmap (+1) [2,3,4]   -- this is [3,4,5]
      fmap (+1) (Just 5)  -- this is Just 6
      fmap (+1) Nothing   -- this is Nothing
      

    所以,这是一种特殊的类型构造函数,与ocaml中的函数几乎没有关系!

    • 在命令式语言中,它是指向函数的指针。
        4
  •  15
  •   Tobu    15 年前

    在OCAML中,它是一个参数化模块。

    如果你知道C++,想一个OcAML函子作为模板。C++只具有类模板,而函子在模块级工作。

    函数的一个例子是map.make; module StringMap = Map.Make (String);; 构建一个使用字符串键控映射的映射模块。

    您不能只使用多态性来实现StringMap之类的功能;您需要对键进行一些假设。字符串模块包含一个完全有序的字符串类型上的操作(比较等),函数将链接字符串模块包含的操作。您可以对面向对象编程执行类似的操作,但是您会有方法间接开销。

        5
  •  13
  •   user276631    14 年前

    你有很多好答案。我会参与进来:

    在数学意义上,函子是代数上的一种特殊函数。它是将一个代数映射到另一个代数的最小函数。”最小值”用函数定律表示。

    有两种方法来看待这个问题。例如,列表是某种类型上的函数。也就是说,给定类型“a”上的代数,您可以生成包含类型“a”的内容的列表的兼容代数。(例如:把一个元素带到包含它的单件列表的映射:f(a)=[a])同样,兼容性的概念由函数定律表示。

    另一方面,给出了一个F“over”A型的函子(即,F a是将函子F应用于A型代数的结果),以及G:A->B的函数,我们可以计算出一个新的函子F=(fmap g),它将F a映射到F b。简而言之,fmap是将“functor parts”映射到“functor parts”的f的一部分,G是将“functor parts”映射到“functor parts”的函数的一部分。将“代数部分”映射到“代数部分”。它需要一个函数,一个函数,一旦完成,它也是一个函数。

    似乎不同的语言使用了不同的算符概念,但事实并非如此。他们只是在不同的代数上使用函子。ocamls有一个模块代数,代数上的函子允许您以“兼容”的方式将新声明附加到模块上。

    Haskell函数不是类型类。它是一个具有满足类型类的自由变量的数据类型。如果您愿意深入研究数据类型的本质(没有自由变量),可以将数据类型重新解释为基础代数上的函数。例如:

    数据f=f int

    与int类同构。所以f,作为一个值构造函数,是一个将int映射到f int的函数,这是一个等价的代数。它是一个函数。另一方面,你不能在这里免费得到正式消息。这就是模式匹配的目的。

    函子有利于以代数兼容的方式将事物“附加”到代数的元素上。

        6
  •  7
  •   Niki Yoshiuchi    15 年前

    在Inria网站上的O'ReillyOCAML书中有一个很好的例子(不幸的是,在写这本书的时候,它已经被删除了)。我在加州理工学院使用的这本书中发现了一个非常相似的例子: Introduction to OCaml (pdf link) . 相关章节是关于函数的章节(书中的第139页,PDF中的第149页)。

    在书中,他们有一个名为makeset的函数,它创建一个由列表组成的数据结构,以及添加元素、确定元素是否在列表中以及查找元素的函数。用于确定是否在集合中的比较函数已被参数化(这就是使makeset成为函数而不是模块的原因)。

    它们还有一个实现比较函数的模块,以便进行不区分大小写的字符串比较。

    使用函数和实现比较的模块,可以在一行中创建新模块:

    module SSet = MakeSet(StringCaseEqual);;
    

    它为使用不区分大小写比较的集合数据结构创建模块。如果您想要创建一个使用区分大小写比较的集合,那么您只需要实现一个新的比较模块,而不是一个新的数据结构模块。

    ToBu比较了C++中的函数和模板,我认为这是非常合适的。

        7
  •  7
  •   JFT    15 年前

    对这个问题的最佳答案可以在布伦特·约基的《类型分类》中找到。

    Monad Reader的这个问题包含了对函数是什么的精确定义,以及对其他概念的许多定义以及一个图表。(monoid,applicative,monad和其他概念被解释和看到与一个函数有关)。

    http://haskell.org/sitewiki/images/8/85/TMR-Issue13.pdf

    摘自类型Classopedia的函数: “一个简单的直觉是,一个函数代表了一些 排序,以及将函数均匀地应用于 集装箱

    但实际上,整个类型Classopedia是一个高度推荐的阅读,这是令人惊讶的容易。在某种程度上,您可以看到这里呈现的typeclass与对象中的设计模式是平行的,因为它们为您提供了给定行为或能力的词汇表。

    干杯

        8
  •  5
  •   Craig Stuntz    15 年前

    这里有一个 article on functors from a programming POV ,然后更具体地说 how they surface in programming languages .

    函数的实际使用是在monad中,如果您查找它,可以找到许多monad教程。

        9
  •  5
  •   Michał Marczyk    15 年前

    考虑到其他答案和我现在要发布的内容,我会说这是一个相当严重的超负荷单词,但无论如何…

    有关haskell中“functor”一词含义的提示,请咨询ghci:

    Prelude> :info Functor
    class Functor f where
      fmap :: forall a b. (a -> b) -> f a -> f b
      (GHC.Base.<$) :: forall a b. a -> f b -> f a
            -- Defined in GHC.Base
    instance Functor Maybe -- Defined in Data.Maybe
    instance Functor [] -- Defined in GHC.Base
    instance Functor IO -- Defined in GHC.Base
    

    所以,基本上,haskell中的函数是可以映射的。另一种说法是,函数是一种可以被视为容器的东西,它可以被要求使用给定的函数来转换它所包含的值;因此,对于列表, fmap 重合 map ,为了 Maybe , fmap f (Just x) = Just (f x) , fmap f Nothing = Nothing 等。

    The Functor typeclass 小节和小节 Functors, Applicative Functors and Monoids 属于 Learn You a Haskell for Great Good 举例说明这个特殊概念在哪里有用。(小结:很多地方!-)

    注意,任何一个单子都可以作为一个函数来处理,事实上,正如CraigStuntz指出的,最常用的函数往往是单子…当然,有时将一个类型作为functor typeclass的实例是很方便的,而不必麻烦将它变成monad。(例如 ZipList Control.Applicative ,提到 one of the aforementioned pages )

        10
  •  5
  •   Community CDub    7 年前

    在对投票最高的人的评论中 answer 用户 Wei Hu 问:

    我了解ml函数和haskell函数,但缺少 将他们联系在一起的洞察力。这两者之间有什么关系 第二,从范畴理论的意义上说?

    注释 :我不知道ML,所以请原谅并纠正任何相关的错误。

    我们首先假设我们都熟悉“category”和“functor”的定义。

    一个简洁的答案是“haskell函子”是(endo-)函子。 F : Hask -> Hask 而“ml函子”是函子 G : ML -> ML' .

    在这里, Hask 是由haskell类型和它们之间的函数组成的类别,类似地 ML ML' 是由ML结构定义的类别。

    注释 :有一些 technical issues 用制造 哈斯克 一个类别,但有很多种方法。

    从范畴理论的角度来看,这意味着 哈斯克 -函数是一个映射 F Haskell类型:

    data F a = ...
    

    和地图一起 fmap Haskell函数:

    instance Functor F where
        fmap f = ...
    

    尽管没有规范,但ml几乎是相同的。 FMAP 我知道抽象,所以让我们定义一个:

    signature FUNCTOR = sig
      type 'a f
      val fmap: 'a -> 'b -> 'a f -> 'b f
    end
    

    那就是 f 地图 毫升 -类型和 FMAP 地图 毫升 -函数,所以

    functor StructB (StructA : SigA) :> FUNCTOR =
    struct
      fmap g = ...
      ...
    end
    

    是函子 F: StructA -> StructB .

        11
  •  4
  •   Sumanth Kumar Mora    8 年前

    “functor是对象和变形的映射,保留了类别的组合和标识。”

    让我们定义什么是类别?

    < Buff行情>

    是一堆东西!

    在A中画几个点(现在2个点,一个是“A”,另一个是“B”)。 立即圈出并命名该圆圈A(类别)。

    < /块引用>

    这个类别是什么?

    < Buff行情>

    每个对象的对象和标识函数之间的组合。

    < /块引用>

    因此,在应用函数之后,我们必须映射对象并保留组合。

    假设“a”是我们的类别,它有对象[“a”、“b”],并且存在一个变形a->b。

    现在,我们必须定义一个函数,它可以将这些对象和变形映射到另一个类别“b”。

    假设函数被称为“maybe”

    data maybe a=nothing_just a
    < /代码> 
    
    

    所以,B类看起来是这样的。

    请画另一个圆圈,但这次用“也许A”和“也许B”代替“A”和“B”。

    一切似乎都很好,所有对象都被映射了

    “a”变成“也许a”,“b”变成“也许b”。

    但问题是,我们也必须将变形从“a”映射到“b”。

    这意味着“a”中的变形a->b应映射到“maybe a”->“maybe b”

    来自a->b的变形称为f,然后来自'maybe a'->'maybe b'的变形称为'fmap f'。

    现在让我们看看“a”中的函数“f”在做什么,看看我们是否可以在“b”中复制它。

    “a”中“f”的函数定义:

    f::a->b
    < /代码> 
    
    

    F拿A还B

    “b”中“f”的函数定义:

    f::maybe a->maybe b
    < /代码> 
    
    

    F拿也许A还可能B

    让我们看看如何使用f map将函数“f”从“a”映射到“b”中的函数“f map f”

    fmap的定义

    fmap::(a->b)->(可能a->可能b)
    fmap f nothing=无
    fmap f(仅x)=just(f x)
    < /代码> 
    
    

    那么,我们在这里做什么?

    我们正在将函数“f”应用于类型为“a”的“x”。“Nothing”的特殊模式匹配来自于函数的定义,可能是

    因此,我们将对象[a,b]和变形[f]从类别“a”映射到类别“b”。

    那是功能!

    是一堆东西!

    在A中画几个点(现在2个点,一个是“A”,另一个是“B”)。 现在圈出并命名一个圆圈(类别)。

    这个类别是什么?

    对象之间的组合和每个对象的标识函数。

    所以,在应用了函数之后,我们必须映射对象并保留组合。

    假设“a”是我们的类别,它有对象[“a”、“b”],并且存在一个变形a->b。

    现在,我们必须定义一个函数,它可以将这些对象和变形映射到另一个类别“b”。

    假设函数被称为“maybe”

    data Maybe a = Nothing | Just a
    

    所以,B类看起来是这样的。

    请画另一个圆圈,但这次用“也许A”和“也许B”代替“A”和“B”。

    一切似乎都很好,所有对象都被映射了

    “A”变为“可能A”,“B”变为“可能B”。

    但问题是我们也必须把变形从“a”映射到“b”。

    这意味着“a”中的变形a->b应映射到“maybe a”->“maybe b”

    来自a->b的变形称为f,然后来自'maybe a'->'maybe b'的变形称为'fmap f'

    现在让我们看看“a”中的“f”函数在做什么,看看我们是否可以在“b”中复制它。

    “a”中“f”的函数定义:

    f :: a -> b
    

    F拿A还B

    “b”中“f”的函数定义:

    f :: Maybe a -> Maybe b
    

    F拿也许A还可能B

    让我们看看如何使用f map将函数“f”从“a”映射到“b”中的函数“f map f”

    fmap的定义

    fmap :: (a -> b) -> (Maybe a -> Maybe b)
    fmap f Nothing = Nothing
    fmap f (Just x) = Just(f x)
    

    那么,我们在这里做什么?

    我们正在将函数“f”应用于类型为“a”的“x”。“无”的特殊模式匹配来自Functor Maybe.

    因此,我们将对象[a,b]和变形[f]从类别“a”映射到类别“b”。

    Thats Functor!

    enter image description here

        12
  •  2
  •   Kevin Greer    10 年前

    不是为了反驳先前的理论或数学答案,而是一个函数也是一个对象(在面向对象的编程语言中),它只有一个方法,并且有效地用作函数。

    一个例子是Java中的Runnabl接口,它只有一种方法:Run。

    考虑这个例子,首先在javascript中,它具有一流的函数:

    [1, 2, 5, 10].map(function(x) { return x*x; });
    

    输出: 〔1, 4, 25,100〕

    map方法获取一个函数并返回一个新数组,其中每个元素都是将该函数应用于原始数组中相同位置的值的结果。

    同样的事情是Java,使用一个函子,你首先需要定义一个接口,比如:

    public interface IntMapFunction {
      public int f(int x);
    }
    

    然后,如果添加一个具有map函数的集合类,可以执行以下操作:

    myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } });
    

    它使用IntmapFunction的内联子类来创建一个函数,该函数与前面的javascript示例中的函数OO等效。

    使用函数可以在OO语言中应用函数技术。当然,一些OO语言也直接支持函数,所以这不是必需的。

    参考文献: http://en.wikipedia.org/wiki/Function_object

        13
  •  2
  •   Dmitri Zaitsev dpedro    8 年前

    粗略概述

    在函数编程中,a 函子 基本上是起重普通的结构 一元的 函数(即只有一个参数的函数)到新类型变量之间的函数。在普通对象之间编写和维护简单的函数并使用函数来提升它们,然后在复杂的容器对象之间手动编写函数要容易得多。另一个优点是只写一次普通函数,然后通过不同的函数重新使用它们。

    函数的例子包括数组、“maybe”和“either”函数,futures(参见 https://github.com/Avaq/Fluture )和其他许多。

    插图

    考虑从名字和姓氏构造完整的人名的函数。我们可以这样定义它 fullName(firstName, lastName) 作为两个参数的函数,但不适用于只处理一个参数的函数的函数。为了补救,我们收集一个对象中的所有参数 name ,现在成为函数的单个参数:

    // In JavaScript notation
    fullName = name => name.firstName + ' ' + name.lastName
    

    如果我们有很多人在一个阵列中呢?我们可以简单地重用我们的函数,而不是手动遍历列表。 fullName 通过 map 为具有短单行代码的数组提供的方法:

    fullNameList = nameList => nameList.map(fullName)
    

    并使用它

    nameList = [
        {firstName: 'Steve', lastName: 'Jobs'},
        {firstName: 'Bill', lastName: 'Gates'}
    ]
    
    fullNames = fullNameList(nameList) 
    // => ['Steve Jobs', 'Bill Gates']
    

    只要我们的每一个入口 nameList 是一个对象,提供 firstName lastName 性质。但是,如果一些物体没有(甚至根本不是物体)呢?为了避免错误并使代码更安全,我们可以将对象包装到 Maybe 类型(SE) https://sanctuary.js.org/#maybe-type ):

    // function to test name for validity
    isValidName = name => 
        (typeof name === 'object') 
        && (typeof name.firstName === 'string')
        && (typeof name.lastName === 'string')
    
    // wrap into the Maybe type
    maybeName = name => 
        isValidName(name) ? Just(name) : Nothing()
    

    在哪里? Just(name) 是一个只装载有效名称和 Nothing() 是用于其他所有事物的特殊值。现在,我们可以简单地重用(提升)我们的原始数据,而不是打断(或忘记)检查论点的有效性。 全名 函数的另一行代码,基于 地图 方法,此时间为maybe类型提供:

    // Maybe Object -> Maybe String
    maybeFullName = maybeName => maybeName.map(fullName)
    

    并使用它

    justSteve = maybeName(
        {firstName: 'Steve', lastName: 'Jobs'}
    ) // => Just({firstName: 'Steve', lastName: 'Jobs'})
    
    notSteve = maybeName(
        {lastName: 'SomeJobs'}
    ) // => Nothing()
    
    steveFN = maybeFullName(justSteve)
    // => Just('Steve Jobs')
    
    notSteveFN = maybeFullName(notSteve)
    // => Nothing()
    

    范畴论

    函数 在里面 范畴论 是两个类别之间关于其形态组成的映射。在一个 计算机语言 ,主要的兴趣类别是 物体 类型 (某些值集),以及 态射 是函数 f:a->b 从一种类型 a 到另一种类型 b .

    例如,取 成为 String 类型, 数字类型,以及 f 函数是否将字符串映射为其长度:

    // f :: String -> Number
    f = str => str.length
    

    在这里 a = String 表示所有字符串和 b = Number 所有数字的集合。从这个意义上说,两者都是 在中表示对象 集合范畴 (这与类型的类别密切相关,这里的区别是不重要的)。在集合类别中, 态射 两个集合之间是从第一个集合到第二个集合的所有函数。所以我们的长度函数 f 这里是从一组字符串到一组数字的变形。

    由于我们只考虑集合类别,因此 函子 从它到它本身是映射发送对象到对象和吗啡到吗啡,满足某些代数定律。

    例子: Array

    数组 可以有很多意思,但只有一件事是函数——类型构造,映射类型 进入类型 [a] 所有类型的数组 . 例如, 数组 函数映射类型 字符串 进入类型 [String] (任意长度字符串的所有数组的集合)和集合类型 Number 进入相应的类型 [Number] (所有数字数组的集合)。

    重要的是不要混淆函数映射

    Array :: a => [a]
    

    用态射 a -> [a] . 函数只是映射(关联)类型 进入类型 [A] 作为一件事对另一件事。每种类型实际上都是一组元素,在这里没有相关性。相反,同态是这些集合之间的实际函数。例如,有一个自然的形态(函数)

    pure :: a -> [a]
    pure = x => [x]
    

    它将一个值作为单个条目发送到一个元素数组中。这个功能是 一部分 数组 函子!从这个函数的角度来看, pure 就像其他功能一样,没有什么特别的。

    另一方面, 数组 函子有它的第二部分——变形部分。它映射了一种形态 f :: a -> b 变成态射 [f] :: [a] -> [b] :

    // a -> [a]
    Array.map(f) = arr => arr.map(f)
    

    在这里 arr 是任意长度的数组,其值类型为 arr.map(f) 数组的长度是否与类型的值相同 ,其条目是应用结果 f 到的条目 ARR .为了使它成为一个函数,将恒等式映射到恒等式和将合成映射到合成的数学规律必须保持不变,这很容易检查 数组 例子。

        14
  •  0
  •   soundyogi    9 年前

    kiss:函数是一个有map方法的对象。

    javascript中的数组实现映射,因此是函数。承诺、流和树通常以函数语言实现映射,当它们实现时,它们被视为函数。该函数的map方法接受它自己的内容,并使用传递给map的转换回调对每个内容进行转换,并返回一个新的函数,其中包含作为第一个函数的结构,但包含转换后的值。

    SRC: https://www.youtube.com/watch?v=DisD9ftUyCk&feature=youtu.be&t=76

        15
  •  -4
  •   feng    10 年前

    在实践中,函子是一个在C++中实现调用操作符的对象。在ocaml中,我认为functor指的是将一个模块作为输入输出另一个模块的东西。

        16
  •  -6
  •   Matt    15 年前

    简单地说,函数或函数对象是一个类对象,可以像函数一样调用它。

    在C++中:

    这就是你写函数的方法

    void foo()
    {
        cout << "Hello, world! I'm a function!";
    }
    

    这就是你如何写一个函数

    class FunctorClass
    {
        public:
        void operator ()
        {
            cout << "Hello, world! I'm a functor!";
        }
    };
    

    现在您可以这样做:

    foo(); //result: Hello, World! I'm a function!
    
    FunctorClass bar;
    bar(); //result: Hello, World! I'm a functor!
    

    这些函数之所以伟大,是因为你可以在类中保持状态——想象一下,如果你想问一个函数被调用了多少次。没有办法以一种整洁、封闭的方式来完成这项工作。对于一个函数对象,它和其他类一样:您将有一些实例变量需要递增 operator () 用某种方法检查这个变量,一切都很好。

        17
  •  -10
  •   alemjerus    15 年前

    函数与函数编程无关。它只是一个指向函数或某种对象的“指针”,可以像调用函数一样调用它。