天天看點

用高階函數做抽象

以函數作為參數,或者以函數作為傳回值,這類能操作函數的函數稱為高階函數

  • 過程作為參數

    普通的求和:

def sum_naturals(n):
        total, k = , 
        while k <= n:
            total, k = total + k, k + 
        return total
           

對立方進行求和:

def sum_cubes(n):
        total, k = , 
        while k <= n:
            total, k = total + k*k*k, k + 
        return total
           

求和下列式子: 81∗3+85∗7+89∗11+...

def pi_sum(n):
        total, k = , 
        while k <= n:
            total, k = total +  / ((*k-) * (*k-)), k + 
        return total
           

三個過程共享着一種公共模式:

def <name>(n):
    total,k=,
    while k <= n:
        total,k = total + term(k),k+
    return total
           

定義求和過程

#求和過程
def sum_term(n,term)#term是一個過程
    total,k=,
    while k <= n:
        total,k = total + term(k),k+
    return total

#整數求和
def term_k(k):
    return k

#K^3求和
def term_k3(k):
    return k*k*k

#式子求和
def term_pi(k)
    return /((*k-)*(*k-))

def sum_pi(k)
    return sum_term(k,term_pi)

#調用過程
>>>sum_term(,term_k)
>>>
           
  • 過程作為一般性方法
def square_root_update(x,a):
    return (x+ a/x)/


def cube_root_update(x,a):
    return ((*x)+a/(x*x))/

def improve(updata,close,guess=):
    while not close(guess):
        guess = updata(guess)
    return guess
def approx_eq(x,y,tolerance=):
    return abs(x-y) < tolerance
#求平方根
def square_root(a):
    def updata(x):
        return square_root_update(x,a)
    def close(x):
        return approx_eq(x*x,a)
    return improve(updata,close)
#求3次根
def cube_root(a):
    def updata(x):
        return cube_root_update(x,a)
    def close(x):
        return approx_eq(x*x*x,a)
    return improve(updata,close)
           

找到函數的不動點: f(x)=x,x稱為f(x)的不動點 ,對于某些函數反複的應用

f(x),f(f(x))f(f(f(x))),....

直到值變化不大時,就可以找到它們的不動點

from math import *
def fixed_point(f,f_guess):
    def close_enough(x,y,tolerance=):
        return abs(x-y)< tolerance

    def try_guess(guess):
        next = f(guess)
        if close_enough(guess,next):
            return next
        else:
            return try_guess(next)
    return try_guess(f_guess)

注意return
           

可以将求平方根看成是一個不動點的問題,求 y2=x的變形y=x/y ,定義sqrt函數:

(使用 f(x)=x/y 會造成結果不收斂,不讓猜測變化太劇烈,答案在y和x/y之間,将猜測值設定為 f(x)=y+x/y2 ,該公式隻是 y2=x 的變形)

def sqrt(x):
    return fixed_point(lambda y:(y+x/y)/,)
           

将函數作為參數傳遞,能夠增強程式設計語言的表達能力。對公共模式進行了抽象。

  • 将函數作為傳回值

    平均阻尼:給定一個函數f,考慮另一個函數,它在x處的值等于x和f(x)的平均值

#平均阻尼,傳入某個函數,傳回x和f(x)的平均值
def damp(f):
    return lambda x:(x+f(x))/
#改寫sqrt,利用damp函數擷取(y+x/y)/2
def sqrt(x):
    return fixed_point(damp(lambda y:x/y),)

#立方根不動點的函數是$y=x/y^2$,定義立方根函數為:
def sqrt(x):
    return fixed_point(damp(lambad y :x/(y*y)),)
           

牛頓法

導數的定義:

Dg(x)=g(x+dx)−g(x)dx

#導數的定義
dx = 
def deriv(g):
    return lambda x:(g(x+dx)-g(x))/dx

>>>deriv(lambda x:x*x*x)()
>>> 
           

如果g(x)是一個可微函數,那麼方程根g(x)=0的解就是函數 f(x)=x−g(x)Dg(x) 的一個不動點

#牛頓轉換
def newton_transform(g):
    return lambda x:x-g(x)/deriv(g)(x)
#牛頓法
def newton_method(g,guess):
    return fixed_point(newton_transform(g),guess)

#牛頓法求平方根,相當于求$g(y)=y^2-x$的g(y)=0的解
def sqrt(x):
    return newton_method(lambda y:y*y-x,)
           

抽象層次高代碼越容易複用,需要一步一步的了解函數直接調用。