精华内容
下载资源
问答
  • 谈谈函数编程

    2020-12-31 02:38:23
    下面看看 redux 是怎么做这个 compose 工具函数的。 <pre><code> javascript // 源自: redux/src/compose.js export default function compose(...funcs) { if (funcs.length === 0) { return arg &#...
  • 很久之前我就学过Lisp和Erlang,但是也就是...可是对函数编程的兴趣一直不减,工作中几乎不会用Scala,但是用的是Java,我一直在想着怎么把Scala用到工作中。最近在写一个工具,因为这个工具基本只有我们项目组用...

    很久之前我就学过Lisp和Erlang,但是也就是写写HelloWorld,写个排序算法。也在Coursera上听过Scala的课,可是那时候我还不怎么用Java,所以后来也没怎么继续。可是对函数式编程的兴趣一直不减,工作中几乎不会用Scala,但是用的是Java,我一直在想着怎么把Scala用到工作中。最近在写一个工具,因为这个工具基本只有我们项目组用,而且很简单,所以我就用Scala写了。以后有机会,把Scala用在生产上。


    为什么对函数式编程这么感兴趣呢。

    第一个原因,可以装逼,或者说是个人兴趣。函数式编程给我们提供了另一种思考问题的方法,最重要的是学习这种思维方法。

    第二个原因,好多人都在学,好多地方都在用。Java 8增加了lambda表达式的支持,连C++都已经支持lambda表达式和闭包。 有越来越多的用函数式编程语言写的开源软件在被广泛使用,最有名的,用Scala写的SparkErlang写的RabbitMQ,当然还有用Lisp写的Emacs。函数式编程语言已经出现四十多年了,为什么现在才火起来,是因为函数式编程语言天然的适合多核编程,或者分布式编程。GoogleMapReduce框架就是受到函数式编程的启发而出现的,其实GoogleMapReduce和函数式编程的map reduce本质上是一样的。


    函数式编程的科学解释


    下面是来自知乎的一段回答,对函数式编程做了比较好的解释。


    编程范式

    函数式编程是一种编程范式,我们常见的编程范式有命令式编程(Imperative programming)函数式编程逻辑式编程,常见的面向对象编程是也是一种命令式编程。

    命令式编程是面向计算机硬件的抽象,有变量(对应着存储单元),赋值语句(获取,存储指令),表达式(内存引用和算术运算)和控制语句(跳转指令),一句话,命令式程序就是一个冯诺依曼机指令序列

    而函数式编程是面向数学的抽象,将计算描述为一种表达式求值,一句话,函数式程序就是一个表达式

     

    函数式编程的本质

    函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。

     

    在函数式语言中,函数作为一等公民,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和返回值,可以对函数进行组合。

     

    纯函数式编程语言中的变量也不是命令式编程语言中的变量,即存储状态的单元,而是代数中的变量,即一个值的名称。变量的值是不可变(immutable),也就是说不允许像命令式编程语言中那样多次给一个变量赋值。比如说在命令式编程语言我们写“x = x + 1”,这依赖可变状态的事实,拿给程序员看说是对的,但拿给数学家看,却被认为这个等式为假。

     

    函数式语言的如条件语句,循环语句也不是命令式编程语言中的控制语句,而是函数的语法糖,比如在Scala语言中,if else不是语句而是三元运算符,是有返回值的。

     

    严格意义上的函数式编程意味着不使用可变的变量,赋值,循环和其他命令式控制结构进行编程。

     

    从理论上说,函数式语言也不是通过冯诺伊曼体系结构的机器上运行的,而是通过λ演算来运行的,就是通过变量替换的方式进行,变量替换为其值或表达式,函数也替换为其表达式,并根据运算符进行计算。λ演算是图灵完全(Turing completeness)的,但是大多数情况,函数式程序还是被编译成(冯诺依曼机的)机器语言的指令执行的。


    一个直观的例子


    在函数式编程里,function is first-class citizen。在函数式语言的代码里,你会发现各种参数都是函数,这与C语言或者JAVA完全不一样。

     

    有这样一个例子,写一个程序对一组二维数据进行拟合。假设我有下面这些数据:

    x :  [1,2,3,4,5]

    y:   [1,4,9,16,25]

    我要写一个函数,来得到这组数据的函数。注意,这时候我们要的结果不再是数据,而是函数。

     

    假设我们要写的函数可以自己学习,每次试一个函数,不行,则继续修正(手工修正)。


    C语言版本:

     

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    int main() {
        int x[5] = {1,2,3,4,5};
        int y[5] = {1,4,9,16,25};
        int a1,a2,a3;
        while(1)
        {
            scanf("%d %d %d",
                &a1,&a2,&a3);
            try(5,x,y,a1,a2,a3);
        }
    }
    int fun(int x,int a1,int a2,int a3) {
        return a1*x*x+a2*x+a3;
    }        
    void try(int len,int *x,int *y,
             int a1,int a2,int a3) {
        int i;
        for(i = 0; i < len; i++) {
            if(y[i] != fun(x[i],a1,a2,a3) ) {
                printf("not match\n");
                return;
            }    
        }
        printf("perfect match\n");
    }



    每次尝试后,就修改一下,最终得到一个a1*x*x+a2*x+a3的函数,实际上是一个系数。

     

    Python版本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    def TRY(X,Y,func):
        = 0
        while i < len(X):
            if func(X[i])!=Y[i]:
                print "not match"
                return
            i=i+1
        print "perfect match"
      
    X=[1,2,3,4,5]
    Y=[1,4,9,16,25]
    while 1:
        func = raw_input()
        TRY(X,Y,eval(func))
      
    appebn@EBNA3PJD:~> python find.py
    lambda x : x*x+5
    not match
    lambda x : x*x*x*x*x*+1
    not match
    lambda x : x * x
    perfect match


    上面的两个程序的不同的地方在于,C语言版的函数是定死的,而Python版的函数可以作为变量输入。在C语言中,变量就是变量,函数就是函数(函数指针指针虽然可以作为参数传给另一个函数,但也是静态的,而且这里的函数更应该叫做routine)。

     

    我们把这个例子扩展一下,假设有海量的数据,我们要用机器学习的方法得到这些数据中的一些规律,这些规律就是函数,而机器就是不断产生新的函数应用于这些数据。试想一下,在这种情况下,当然是函数式编程更理想。未来的IT系统,都是分布式的,数据都是海量的,传统的锁机制已经不能适应这种分布式编程了,而函数式编程就是一种可以在语言级解决问题的一个方法,当然不是所有问题都能解决。




    函数式语言的代码更加简洁易懂



    写函数式编程语言时,最难的是转变思想。例如计算一个数组的和,

    C语言:

    1
    2
    3
    4
    5
    int a[5] = {1,2,3,4,5};
        int sum = 0;
        forint i = 0;i<5;i++) {
            sum +=a[i];
    }



    用函数式编程语言写(Python,也可以用上面的for循环,不过那就和用C++写C语言程序一样了):

    1
    2
    = [1,2,3,4,5]
    sum = reduce(lambda x,y:x+y, a,0)

    这里的reduce的作用是:

    有一个累计值acc0reduceacc=acc+y应用到每个a的元素上,最后就得到了a的各个元素的和。

     

    GoogleMapReduce就是受函数式编程语言的mapreduce启发而产生的(reduce在有的语言中叫fold,就是把列表折叠一下)

    比如我用python写一个WordCount,给一个字符串数组,返回其中某个单次的个数。

    思路:找"a"的个数,将["a","b","c","a"]映射成[1,0,0,1],再求和

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #这个函数返回的是一个函数
    #判断一个词是不是等于word,如果等于word,返回1,否则返回0
    #在函数式编程语言中,到处倒是可以返回函数的函数
    def isTargetWord(word):       
        def isWord(w):        
          if == word:                
            return 1    
        else:       
          return 0
        return lambda x: isWord(x)
            
    words = ["fuck","bitch","fuck"]
    print "fuck:",reduce(lambda x,y:x+y,map(isTargetWord("fuck"),words),0)
    print "bitch:",reduce(lambda x,y:x+y,map(isTargetWord("bitch"),words),0)


    pythonlambda表达式里不支持if-else,如果用scala

    1
    2
    val words = List("fuck","bitch","fuck")
    println("fuck:" + words.map( x=>if(x=="fuck"1 else 0).reduce((x,y)=>x+y))

     

    这种语法,先map,在reduce,看起来比较自然。一但理解了函数式编程语言,那么代码将会变得特别简洁易懂。当然让一个从来没学过函数式编程的人看上面的代码,肯定一头雾水,一但懂了,就觉得写起来特别方便。



    总结


    总之,对于一个热爱技术的人,一定要学一下函数式编程。



    本文转自nxlhero 51CTO博客,原文链接:http://blog.51cto.com/nxlhero/1661813,如需转载请自行联系原作者

    展开全文
  • 没有学不会的python函数是什么?老调常谈,还是那老一套,学习一个东西前,先搞懂是什么,再来学习怎么用。函数函数,如果你是刚经历过高考肯定很熟悉,数学中就经常出现这个名词,比如什么sin函数,cos函数之类的。...

    没有学不会的python


    函数是什么?

    老调常谈,还是那老一套,学习一个东西前,先搞懂是什么,再来学习怎么用。

    函数函数,如果你是刚经历过高考肯定很熟悉,数学中就经常出现这个名词,比如什么sin函数,cos函数之类的。哈哈,心疼一会高考生。

    函数是什么呢?其实函数严格来说,可以分为数学函数以及计算机函数,数学函数嘛,大家都是有文化的人,应该都知道,且我讲的是编程,数学函数跟这个关系不大,这里就略过了。我们主要讲计算机函数。

    计算机函数是什么?

    官方的解释是这样的:

    函数是指一段在一起的、可以做某一件事儿的程序。也叫做子程序、(OOP中)方法。

    其实这段解释已经很直白了,对于初学者来说,困惑的点就是子程序这个词。在写代码的过程中,往往由于业务逻辑比较复杂,各种数据交互流程比较繁琐,出于数据安全、易于理解、松耦合、强内聚等特征的考虑,我们会把程序划分成多个模块,每个模块又划分多个类和多个函数。由于上述现象的出现,一个大的程序模块就有很多小的模块组成,然后在大的模块中会调用小的模块以实现某个功能点,此时小的模块就成为了子模块,也叫做子程序。

    简单说吧,子程序就是一个实现特定功能的程序块,通常被主程序调用。

    嗯,现在把子程序讲清楚了,那么这个跟函数有什么关系?其实吧,子程序换一种说法,也可以称作是函数。在不同的语言中,有时也称为方法,但在python中,如果子程序是处于模块中的就称作函数,如果是处于类中的,就称作方法。由于我这个系列里还没讲到面向对象,所以,我们忽略掉类的方法这个说法,现在暂且认为,子程序就是函数。

    做一个比较形象的例子:

    c95d695835b8baa6c0b67b52991ce579.png

    假设上述人的一天是主函数,那么吃饭上班睡觉就是子函数,只有在主函数中调用了子函数,才能组成人的一天。

    函数有什么作用?

    既然函数存在,那么就有它存在的道理。它的作用不仅有,而且特别重要。下面就随便列几个,更多的我就不说了,因为如果你没有编程基础的话,很多特性说了也理解不了,等于白说。

    1. 高内聚、低耦合---这个是编程语言中的一个非常重要的特征,尤其是面向对象语言中。高内聚指的是,实现同样目的的代码应该尽量放在一块,不要松散。低耦合指的是,函数与函数之间尽量解耦,不要处处关联,这样才不会出现一发而触动全身的情况。即不会因为改了某个函数的一句话,导致其它函数也不能用了。
    2. 易拓展---需求是跟着市场和甲方走的,产品要改需求,程序员就得加班,如果程序的代码结构很好,那么我们就可以只改需要改的函数,其它的不动,比如增加功能模块,增加参数。
    3. 可重复使用---当把某个功能代码高度集中在函数里面时,此函数就不依赖于其它函数而存在,因此,任何需要实现该功能的函数都可以通过调用这个函数来获取该功能。
    4. 易于理解---通过函数名称以及文档描述和注释,可以让自己以外的人更好的参与进来,而函数的存在,对于这种分工合作是个很好的表现形式,大家都不需要知道函数怎么实现的,只需要调用就可以了。

    还有更多,以后你就会慢慢发现了。

    如何定义函数?

    函数的定义很简单,看下面:

    def function_name(prama1,prama2):
        pass

    def的意思就是声明后面的语句块是一个函数,function_name就是函数名称,param1、param2就是参数。到了这里,我有必要再说一下,因为面对着没有基础的同学,难免要多说一点,避免他们走弯路。我要说的是函数名称不是写死的function_name,上面的只是一种表现形式。就好比大家都有名字,但是我们大家都不叫名字,有的叫刘亦菲,有的叫马云。函数名称应该是根据所实现的功能来定的,参数名称也类似。

    这里说一下什么叫做参数,参数可以看作是一个因变量,只有传入了参数,才能使函数产生不同的结果。参数不是函数必须的,可以构造一个不需要参数的函数,但是这个函数总会产生相同的结果。

    下面看一下函数的示例:

    def my_sum(param1, param2):
        return param1 + param2
    
    
    def my_diff(param1, param2):
        return param1 - param2

    完了吗?那肯定不是,哪有这么简单。结合我自己的编程经验,还有以下的功力要传授给你们。

    函数名称要有实际意义,切记假大空,更忌讳的是取一个毫无关系的名字

    比如:我想定义一个扫描字符串的每个字符并输出的函数。有下面三个写法:

    def scan_str(content):
        for s in content:
        print(s)
    
    
    def scan(content):
        for s in content:
        print(s)
    
    
    def a(content):
        for s in content:
        print(s)

    第一个函数最优,从名字就看得出来就是扫描字符串。第二个次之,从名字看到出来是扫描,但是扫描啥不知道,扫描文件还是扫描病毒还是其他的?这就是范围过广,也就是假大空。第三个写出来是要被骂的,而且是往死里骂的那种,从函数名字根本看不出来是什么意思。你想象一下啊,如果一个几万行代码含有几百个函数的程序,全部名字都是abcd这样的名字,你会不会看疯掉?

    函数应该要加上文档说明,复杂的语句要加上注释说明

    这么做的原因是,一来方便日后自己查看代码,二来是方便别人接手你的代码。添加文档说明的方式如下:

    def scan_str(content):
     """
        扫描字符串的每个字符并输出
        :param content: 待扫描的内容
        :return: 不返回任何结果
        """
        for s in content:
            print(s)

    就是在函数声明下面,真正的代码实现逻辑上面,输入三次双引号就会自动生成一个待填充的文档说明结构,含有功能描述,参数描述以及返回值描述。未填充前的代码是这样的:

    def scan_str(content):
     """
    
        :param content: 
        :return: 
        """
         for s in content:
             print(s)

    函数的代码块不易过长,一般维持在15行以内为佳

    代码语句块过长说明我们的功能划分的还不够细致,过于短说明我们过于精简,一般维持在15行以内为佳。当然这不是硬性标准,它不会报任何异常。只是这个是默认的python pep8国际编码规范,很多大公司都会有代码规范考核的,从一开始掌握这些对我们有好处。 是

    函数的参数值和传参

    上面有简单讲了参数是什么。但这还远远不够,python中的参数,是非常灵活且有趣的。目前来说,可分为四类,分别是必须参数、可选参数、位置参数、关键词参数。下面就这些一个个来说。

    必须参数
    必须参数就是必须要传递的参数,如果不传递就调用函数会报TypeError。比如我如果这样调用函数,就会报错:

    def scan_str(content):
     """
        扫描字符串的每个字符并输出
        :param content: 待扫描的内容
        :return: 不返回任何结果
        """
         for s in content:
             print(s)
    
    
    scan_str()

    由于scan_str有一个content参数,这个是必须参数,如果你不传递就调用这个函数,会爆出如下异常:

    Traceback (most recent call last):
     File "D:/code/python/blog/main.py", line 11, in <module>
        scan_str()
    TypeError: scan_str() missing 1 required positional argument: 'content'
    

    这个意思是说,缺少了一个必须的参数content,也即是我们调用它的时候必须要传递一个参数。嗯,好现在我们知道必须要传递参数了,但还有一点,传递的参数数据类必须要正确,不信你看下面这个例子:

    def scan_str(content):
     """
        扫描字符串的每个字符并输出
        :param content: 待扫描的内容
        :return: 不返回任何结果
        """
         for s in content:
             print(s)
    
    
    scan_str(100)

    我们知道这个函数是扫描字符串并输出每个字符,我们期望传入的参数是字符串,但是我们这里却传入了一个整型参数100,它同样会抛出TypeError异常,抛出的异常如下:

    Traceback (most recent call last):
     File "D:/code/python/blog/main.py", line 11, in <module>
        scan_str(100)
     File "D:/code/python/blog/main.py", line 7, in scan_str
     for s in content:
    TypeError: 'int' object is not iterable

    意思是,整型对象是不可迭代的。因此,我们要注意传递的参数类型要正确,或者在代码块里面添加一个参数类型检查函数。比如:

    def scan_str(content):
     """
        扫描字符串的每个字符并输出
        :param content: 待扫描的内容
        :return: 不返回任何结果
        """
         if isinstance(content, str):
             for s in content:
                 print(s)
         else:
             print("你传入的参数不是字符串类型")
             exit(0)
    
    
    scan_str(100)
    

    这里,我们用isinstance函数来检测传入的参数是不是字符串类型。isinstance是python标准库里面的函数,我们可以直接拿来用。必须参数要注意的就是这么多。

    默认参数

    默认参数就是含有默认值的参数,也叫做可选参数。为什么呢?因为默认参数有默认值了,即使我们不传递参数,它也是有值的。当然如果默认值不符合我们的需求,我们可以同样可以传递一个新的值把它覆盖掉。假如我们有如下一个函数:

    def scan_str(content="default"):
     """
        扫描字符串的每个字符并输出
        :param content: 待扫描的内容
        :return: 不返回任何结果
        """
         if isinstance(content, str):
             for s in content:
                 print(s)
        else:
            print("你传入的参数不是字符串类型")
            exit(0)
    
    
    scan_str() # 输出默认值
    scan_str("cover default value") # 覆盖默认值
    

    与前面不同的是,这里的content有一个默认的值,所以我们可以不带任何参数的调用此函数,此时函数不会报错并且会输出default。同样的,我们要是想输出其它字符串,只需要传递一个参数值覆盖掉默认值即可。

    但是有一点要注意的是,默认值必须是不可变类型。比如上面的是字符串类型,就是不可变类型,如果是可变类型的话,比如列表,此时,默认值会随着函数的调用发生改变,和我们最初预期的默认值会不一样。

    看下例子:

    def print_default_list(my_list=[1, 2, 3]):
     """
        输出默认数组的内容
        :param my_list: 默认数组
        :return:
        """
        print(my_list)
        my_list.append(4)
    
    
    # 连续两次调用了此函数,会发现输出的列表内容发生了变化
    print_default_list()
    print_default_list()

    运行结果:

    [1, 2, 3]
    [1, 2, 3, 4]

    按照我们的预期my_list应该是【1,2,3】才对,因为4是输出之后才添加上去的。但如果有学习过我们前面讲到复合类型的文章了解过不变类型和可变类型的区别的同学,应该明白它们的区别。因为my_list是列表,它是可变对象,也即它其实引用了一个内存地址块,无论我们调用多少次,这个地址都是不变的,但是因为我们添加了4,导致该内存块又添加了一个新的内容,所以my_list的内存地址是没有变的,只是内存保存的数据变化了。因此,我们第二次调用此函数的时候,发现默认值已经被修改了。所以记住:

    默认值一定要是不可变类型,否则会出大事的。

    位置参数
    位置参数一般是在我们不确定该函数应该要声明多少个参数,或者要声明的参数实在太多的时候,用来占位使用的。

    示例代码:

    def print_args(*args):
     """
        输出位置参数
        :param args:
        :return:
        """
        for item in args: 
        print(item)
    
    
    print_args(1, 2, 3, 4)
    print_args("hello ", "world")

    上述代码就是循环输出所有传递进去函数的参数,我们可以看到,第一次调用的时候传递了4个,第二次调用的时候传递了2个。这就是不一定要传输多少个参数,传多少都行,根据业务需求来定。位置参数一般使用*args来表示。

    深度剖析一下为什么会这样,其实这涉及到装箱和拆箱的说法。即当我们调用print_args(1,2,3,4)的时候,我们看上去好像是传递了4个参数,其实不是,在传递的过程中,python帮我们装箱了,即传递过去的其实是一个元组(1,2,3,4),这也是为什么可以迭代输出的原因。我们可以通过代码来观察一下:

    def print_args(*args):
     """
        输出位置参数
        :param args:
        :return:
        """
        print(type(args))
        print(args)
    
    
    print_args(1, 2, 3, 4)

    输出如下结果:

    <class 'tuple'>
    (1, 2, 3, 4)

    可以观察到,结果确实和我们预期的一样,args的类型是元组。装箱的过程可以通过下图来理解:

    b3f2459d7455fa368dc516fd22b26064.png

    关键词参数

    关键词参数即是我们常说的字典,就是key=value这样形式的,明白吗?因为有键,所以叫关键词参数。关键词参数一般用**kwargs表示,前面是两个*号。关键词参数的用法如下:

    def print_kwargs(**kwargs):
     """
        输出关键词参数
        :param args:
        :return:
        """
        print(type(kwargs))
        print(kwargs)
        for k, v in kwargs.items():
            print("{0}:{1}".format(k, v))
    
    
    print_kwargs(one=1, two=2)

    通过代码可以看到,即使函数没有定义one、two这两个参数,但是我们依然可以以键值对的形式传进去,原因是python对它进行了装箱操作,它传递给函数的时候是这样的one=1,two=2,然后经过python的处理,函数接收的时候已经是这样了{"one":1,"two":2}。

    我们看下输出结果:

    <class 'dict'>
    {'one': 1, 'two': 2}
    one:1
    two:2
    

    可以发现,关键词参数其实就是字典,对吧?装箱过程如图所示:

    ad1e78186b631b636b81da1f8bf96d33.png

    好了,碍于篇幅的问题,主要是我的脑力槽到底了,今天先讲到这里,这么多也够大家消化一些时间的了。加油。下一篇将继续将函数的综合应用、函数的返回值、lambda函数...感兴趣的朋友可以留意一下。

    喜欢我的系列文章的话,可以关注我的主页也可以关注我的公众号。

    baa81020fd981a4be9489cc3a99e68cc.png

    如果你有什么问题想要反馈或者联系我,可以加我。

    64c25390a00b33f1077e16959c31ad14.png
    展开全文
  • 从闭包谈函数编程

    2019-10-02 07:58:33
    讲的是函数编程,那个时候看了一遍,懵懵懂懂,只有一个感觉,函数编程怎么好像讲的都是数学公式(说句实话,我那个时候还真不理解boss为什么给我发那篇paper,只是想反正多看点东西总不会错)?最近一段时间,...

    记得开始学习golang的时候,boss给我发了一篇paper,讲的是函数式编程,那个时候看了一遍,懵懵懂懂,只有一个感觉,函数式编程怎么好像讲的都是数学公式(说句实话,我那个时候还真不理解boss为什么给我发那篇paper,只是想反正多看点东西总不会错)?最近一段时间,go用的比较多,业务逻辑让我思考了很多问题,虽然go并非函数式语言,但却支持了很多函数式的概念,让编程变得简单。当然,在写代码的过程中,我就很怀疑,使用了函数式编程会不会导致运行效率变低?

     

    这篇文章就从几方面学习函数式编程(by 魏加恩)

    1. 数学公式和函数式编程有什么关系

    2. 函数式编程有什么特点,go支持了哪些概念

    3. 函数式编程与运行效率

     

    1. 数学公式和函数式编程有什么关系

        举个简单例子吧,数学中有一个概念叫做映射(y=f(x)),说的通俗一点就是函数啦。而最熟悉的应该就是二次函数(抛物线y=a*x*x+b*x+c)

        现在coding实现求抛物线上某一点的值,我们知道a,b,c是参数,x是自变量,y是因变量,如果是以前,我也许会这么实现(为了纪念我许久未写的c++,还是用c++来写一下)

    double getParabola(double a,double b,double c,double x) {
         return a*x*x+b*x+c;
    }
    

      好了,问题来了,

         问题一、给定抛物线,求x=2,x=3,x=4时的值,就是下面的做法了

    resultA = getParabola(a,b,c,2) 
    resultB = getParabola(a,b,c,2) 
    resultC = getParabola(a,b,c,2) 
    

      这在程序中,是很正常的做法。但是,如果从数学的角度来看,有没有办法变得符合数学公式思维呢?以下是我的另外一种实现(这里用go来实现哈,因为c++我知道怎么写),

    func getParabola(aa,bb,cc float32){
        var a = aa
        var b = bb
        var c = cc
    
        a := func(x float32) {
               return a*x*x+b*x+c
        }
    
        return a
    }
    

      然后,同样是对于问题一,解决方案如下

    parabola := getParabola(a,b,c)
    
    resultA := parabola(2)
    resultB := parabola(3)
    resultC := parabola(4)
    

      是不是跟求函数值一样?所以,数学关系在函数式编程中得到了很好的体现。

    2. 函数式编程有什么特点,go支持了哪些概念

        函数式编程有三大特性

        1. 变量的不可变性: 变量一经赋值不可改变。如果需要改变,则必须复制出去,然后修改。 go中,string变量一经赋值,不可以像c++那样,c[2]='a'这样的修改,而是要显式转化为[]byte,然后进行修改。但是已经是另外一块内存了。

        2. 函数式一等公民: 函数也是变量,可以作为参数,返回值等在程序中进行传递。 这个特性,c++和go应该都是支持的。

        3. 尾递归:递归的概念在斐波那契数列的时候,就学习过了。如果递归很深的话,堆栈可能会爆掉,并导致性能大幅度下降。而尾递归优化技术,编译器如果支持的话,可以在每次递归时重用stack(尾递归表示递归调用发生在最后一步,这个时候,之前的结果都作为参数传递给最后一步的调用,所以之前的状态就没有任何作用了,所以可以重用stack)。 go是否支持,这个我暂时不清楚。

       函数式编程常用技术

       1. map&reduce&filter

           map用于对每一个输入,调用同一个函数,产生一个输出,比如c++中的for_each,hadoop里面的map,python的map等。

       reduce用于对每一个输入,加上上一个输出,得到下一个输出,比如python和hadoop中的reduce,

           filter用于做过滤,比如c++的count_if等。

       2. 递归

       3. pipeline  

          把函数实例放到一个数组或是列表中,然后把数据传给这个action list,输入顺序地被各个函数所操作(意思是每一个函数的输出,作为另外一个函数的输入,数据是流动的,计算是固定的,类似storm的概念),最终得到我们想要的结果。

       4. 其他(有待进一步学习)

     

    3. 函数式编程与运行效率

        函数式编程最重要的一个概念就是函数式一等公民,函数跟变量是一样的。可以作为参数,返回值等。不赞成使用赋值语句,所以比较多的使用递归,所以函数式编程效率肯定会比较低。

       最近我用的比较多的是闭包,闭包的概念就是一个环境(一个或多个变量)加上一个函数,每一次对闭包表达式求值,都得到一个隔离的结果,这跟普通函数是不一样的,普通函数就是一段可执行的代码,只要入口确定了,调用的位置也就确定了。举个例子,上面抛物线的例子,调用

    a:=getParabola(0.2,0.1,0.3)
    b:=getParabola(0.1,0.1,0.4)
    

      得到的是两条抛物线。之所以我觉得效率会降低,是因为闭包本身就是一个求值赋值的过程,涉及到变量的创建销毁。当然,我没有实际去测试性能。如果后续发行server效率降低,也许这是一个需要考虑的地方。

     

    这篇文章只是最近一段时间写代码的一个感性认知加上网上查找一些资料。作为一个备忘,后续可以深入学习。

     

    转载于:https://www.cnblogs.com/weijiaen/p/3977834.html

    展开全文
  • 开始自学Python,Python中有一个重要的函数是 del函数,只要过Python的朋友对它就一定不会陌生,它也算是在学习Python过程中一个不容易弄懂的点了,今天我们就简单来讲一下del函数到底是怎么用的。 python中的del...

    Python真是太火了,最近我也入了Python的坑,开始自学Python,Python中有一个重要的函数是 del函数,只要学过Python的朋友对它就一定不会陌生,它也算是在学习Python过程中一个不容易弄懂的点了,今天我们就简单来讲一下del函数到底是怎么用的。

    python中的del用法比较特殊,新手学习往往产生误解,弄清del的用法,可以帮助深入理解python的内存方面的问题

    python的del不同于C的free和C++的delete。

    由于python都是引用,而python有GC机制,所以,del语句作用在变量上,而不是数据对象上。

    初学 Python,想要弄明白Python 的del函数的简单使用可能有点复杂,可以看看下方视频,听知名技术专家李刚老师对Python列表与元组的简单使用的详细解析,

    李刚老师出版的《疯狂Java》系列图书曾得到市场的广泛认可,经过多次再版,并被多家高校选作教材。上方视频来自于李刚老师的在线视频课程《21天通关Python》第二章 第九节Python列表与元组的简单使用。

    大家都有学习Python的困惑,今天就给大家推荐一本巨有影响力的Python实战书,上线时间仅2个月,就超越了众多实力派,成京东和当当网上的长期畅销图书,并且收获了3.4W的五星好评。

    这本书可谓是笔者独家私藏图书之一了,对我学习Python有着莫大的帮助,在京东上也常常"断货",这次拿出来给大家分享一下,希望能帮到大家。

    《21天通关Python》视频课程以畅销图书为教材,由图书作者李刚亲自操刀讲解;上手门槛低,可作为0基础掌握Python教材;书籍+线上复合型学习场景特别适合Python小白学习!

    点击查看课程:https://edu.csdn.net/bundled/detail/49?utm_source=jiansuopy9_1

    (含图书邮寄+视频教程+社群答疑+导师带队)笔者跟大家分享一个福利!下单时输入优惠码csdn66,立减20元,券后仅需99元!

    扫码入Python技术交流群,可免费听技术讲座+领学习资料+视频课免费看!
    在这里插入图片描述

    展开全文
  • 学编程1个月感受

    2019-07-23 14:44:53
    接下来就是函数,模块调用,因为这个伤心了一个多星期,怎么调用怎么都是错的,后来无聊的时候偶然发现是自己一直都没调用真确的语法格式。继续学习。 到现在一个月多了,反而感觉越越不懂了。随便一个时间模块都...
  • 学习编程的一点感想

    2013-10-13 19:14:54
    我现在看汇编win32编程,颇多感慨。过去的在IDE中拉拉控件,编点...汇编恰恰是个桥梁,让我理解了很多系统底层的东西,例如蠕虫和病毒根本就是两回事,缓冲区溢出是怎么发生的,有些C函数中对数组界限的不检查导致被
  • 学编程的感受

    2009-05-08 23:09:00
    高考完填志愿时由于对计算机喜欢,看到软件这个...可是一C语言,就被难住了,第一章的一个小例子就把我给难住了,一个小小的例子说到了函数调用,一点也搞不明白,此时感觉到了压力所在,发现自己什么都不会,什么都
  • 这让你的学习变得困难,你应当先去学习对编程中常用的术语以避免对相关教程的理解偏差(廖雪峰的网站中内容比较基础,但也不会对这些基础名词做解释的,因为解释这些需要太大的篇幅,而其中的知识量又很少)。...
  • 看前点赞 养成习惯 学习编程,想看干货,关注公众号:不会编程的程序圆 各位同学,你觉得你数组学会了吗?不妨看看下面的问题,你能看一眼程序就回答上来吗?引子:观察下面的程序,这个程序有安全隐患吗?#include&...
  • 没有学不会的python函数是什么?老调常谈,还是那老一套,学习一个东西前,先搞懂是什么,再来学习怎么用。函数函数,如果你是刚经历过高考肯定很熟悉,数学中就经常出现这个名词,比如什么sin函数,cos函数之类的。...
  • 但是相信我,在别的编程语言中,会很麻烦,比如“ System.out.println(要打印的文本) ”这种命令结构很重要,print是一个函数,一个在计算机世界中接受输入的函数,同时它也生成输出,这个函数不会返回任何东西,...
  • 第一阶段:Python入门(框架再怎么变,基本语法不会变,基础中的基础) ·数据类型 ·循环判断 ·常用模块 ·函数、迭代器、装饰器 ·递归、迭代、反射 ·面向对象编程 第二阶段:WEB前端基础(坑比较多,多...
  • 英文编程中不管是语法还是函数都是英文及阿拉伯数字构成的,所以确实很容易给人一种不会英语怎么编程的错觉。 看见错觉,就知道我想说的答案是什么了吧,是的!编程和英语几乎没有什么直接关系,这里还是拿C语言的...
  • 对于很多编程初学者来说,递归算法是学习语言的最大障碍之一。很多人也是半懂不懂,结果到很深的境地也会因为自己基础不好,导致发展太慢。可能也有一大部分人知道递归,也能看的懂递归,但在实际做题过程中,却不...
  • 1.幂等性幂等(idempotent、idempotence)是一个数学与计算机概念,常见...这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 123
精华内容 49
关键字:

不会函数怎么学编程