• named let 递归和闭包的利器


    named let和递归,闭包联系十分密切.而且还是提高性能的重要手段.先来看一个make-list函数的模拟,最原始的写法大概是:

    (define (imake-list n member)
        (if (= 1 n)
            (cons member '())
            (cons member (imake-list (- n 1) member))))

    这种写法的毛病在于:

    1.递归过程中,member变量可能需要在全局作用域中查找,比局部作用域查找要慢.

    2.member是一个固定的参数,然而递归过程在不断重复将它传入imake-list.

    这个时候你需要 named let,完美解决这2个问题:

    (define (imake-list n member)
      (let recur ((n n))
        (if (= 1 n)
            (cons member '())
            (cons member (recur (- n 1))))))
    
    (imake-list 5 "a")

    具体过程:

    1.let创建了一个内部函数recur.它接受一个参数,返回一个列表.

    2.imake-list的n传递给了recur的n.而后者是在局部作用域.

    3.递归过程转移到recur中进行,固定参数member成了它的自由变量.避免了重复传入的问题.

    似乎迭代和递归会很频繁地用到这种技巧,例如很基本的函数map的模拟,也可以分为2个版本:

    ;原始低效版
    (define (imap f x . y)
      (if (null? y)    
          (if (null? x)
              '()
              (cons (f (car x)) (imap f (cdr x))))
          (if (null? x)
              '()
              (cons (apply f (car x) (imap car y)) (apply imap f (cdr x) (imap cdr y))))))
    
    ;named let高效版
    (define (imap f x . y)
      (if (null? y) 
          (let recur ((x x)) 
            (if (null? x) 
                '() 
                (cons (f (car x)) (recur (cdr x))))) 
          (let recur ((x x) (y y)) 
            (if (null? x) 
                '() 
                (cons (apply f (car x) (imap car y)) (recur (cdr x) (imap cdr y)))))))
    
    (map + '(1 2 3) '(1 2 3) '(1 2 3)) 
    (imap + '(1 2 3) '(1 2 3) '(1 2 3)) 
  • 相关阅读:
    每日博客
    每日博客
    预开发软件书 新
    laravel的优点
    Laravel 自己创建ServiceProvider 与 yansongda/laravel-pay 支付服务
    laradock
    普通静态绑定与后期静态绑定
    phpstorm和xdebug的配置 变量的单步调试
    phpstorm 连接远程docker
    docker php-fpm安装xdebug 与phpstorm firefox联调
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3390253.html
Copyright © 2020-2023  润新知