zoukankan      html  css  js  c++  java
  • Scheme call/cc 研究

    目前尚不清楚实质,但已经能够从形式上理解它的某些好处,有个很简单的连乘函数可以说明:

    为了展示究竟发生了什么,我包装了下乘法函数,将其变为mul.

    我们将比较product和xproduct的区别.

    ;包装乘法函数
    (define (mul x y) 
      (display x) 
      (display " * ")
      (display y)
      (newline)
      (* x y))
    
    
    ;常规版
    (define (product ls)
      (let f ((ls ls))
        (cond
          ((null? ls) 1)
          ((= (car ls) 0) 0)
          (else (mul (car ls) (f (cdr ls)))))))
    
    ;call/cc版
    (define xproduct
      (lambda (ls)
        (call/cc
         (lambda (break)
           (let f ((ls ls))
             (cond
               ((null? ls) 1)
               ((= (car ls) 0) (break 0))
               (else (mul (car ls) (f (cdr ls))))))))))
    ;比较
    (product '(1 2 3 4 5))
    (xproduct '(1 2 3 4 5))
    (product '(1 2 3 0 5))
    (xproduct '(1 2 3 0 5))

    结果:

    5 * 1
    4 * 5
    3 * 20
    2 * 60
    1 * 120
    120
    5 * 1
    4 * 5
    3 * 20
    2 * 60
    1 * 120
    120
    3 * 0
    2 * 0
    1 * 0
    0
    0

    我们可以看到,对不含0的连乘,两个函数的内部运行是一样的.

    然而对于包含0的连乘,call/cc的方式就显得比较合理.

    product碰到0,即使能够中止递归过程,返回一个0,也仅此而已,它仍然需要笨拙地把这个0和前面已经存在的数进行连乘.

    而人脑认为这是愚蠢的,因为只要发现有一个0,那么无论其他数是怎样的,最终结果必然是0,所以直接返回0就可以了.

    call/cc正是在模拟人脑这一想法.

    下面展示xproduct函数,对于(1 2 3 0)和(1 2 3 4)两种情况,它的函数体分别是怎么展开的:

    > (call/cc (lambda(break)(* 1(* 2(* 3 (break 0))))))
    0
    > (call/cc (lambda(break)(* 1(* 2(* 3 (* 4 1))))))
    24
    (let 
        ((@ (lambda (x) (display "@") x))
         (* (lambda (x) (display "*") x))
         (f (lambda (x) x)))
      ((@ (call/cc f))(* (call/cc f))))
  • 相关阅读:
    决策树分类
    集群服务器 获取COOKIE错误
    React 自写Loading
    HTB-靶机-Unattended
    HTB-靶机-LaCasaDePapel
    HTB-靶机-FriendZone
    HTB-靶机-CTF
    HTB-靶机-FluJab
    HTB-靶机-Help
    HTB-靶机-Chaos
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3436097.html
Copyright © 2011-2022 走看看