• 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)) 
  • 相关阅读:
    利用ApplicationListener和ContextRefreshedEvent加载自己的beanPool
    java对象转变为map
    Java通过poi创建Excel文件并分页追加数据
    Java通过poi读取excel中文件
    SpringMvc通过controller上传文件代码示例
    SpringCloud组件学习-图
    Java-线程间通信小结
    Java-关于Thread
    Java-对象及变量的并发访问小结
    java爬取免费HTTP代理 code-for-fun
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3390253.html
Copyright © 2020-2023  润新知