• 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)) 
  • 相关阅读:
    PA
    核电站问题(codevs 2618)
    [转]SQL SERVER 的排序规则
    C# 窗体控件输入框大写
    查看哪些端口被使用
    [转]Windows服务“允许服务与桌面交互”的使用和修改方法
    [转]OBJECT_ID 有哪些种类
    如何:对 Windows 窗体控件进行线程安全调用
    老人手机不要买山寨机
    VBA文本型数字变成数值
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3390253.html
Copyright © 2020-2023  润新知