Scheme之功能分解和封装内部函数/块结构

待解决的问题:输出0-x之间 3的倍数而且含5的数,如15,54,555等等(或者输出这种数的个数)。

在《编程导论(Java)》中以这个例子介绍结构化分解。所以用Scheme实现一下。

package semantics.method;
public class HelperMethodDemo{
    //简单情况:输出0-x 之间 3的倍数而且含5的数. //////
    private static boolean is3X(int n){
        return ( n%3 == 0);
    }
    private static boolean isInclude5(int n){
        while ( n != 0){
            if (n % 10 == 5) return true;
            n /=10;
        }
        return false;
    }

    /**采用功能分解。觉得这个问题有点难,需要分解*/
    static void foo(int x){
        for(int i=0;i < x;i++){
            if( is3X(i) && isInclude5(i) ){
                System.out.print(" "+i);
            }
        }
    }

    /**不需要分解。觉得这个问题较容易。 */    
    static void foo_0(int x){
        for(int i=0;i < x;i++){
            if(i%3== 0){ 
                int m = i; 
                while(m!=0){
                    if(m%10 == 5 ){
                        System.out.print(" "+i);
                        break;
                    }
                    m/=10; 
                }//end while                
            } 
        } 
    }
}
【解】按照功能分解的基本思想:对于较复杂的问题,分解成较简单的小问题,而后通过函数调用解决该问题。上述问题可以分解为:(1)一个数是否3的倍数,由函数is3X?实现;(2)一个数是否包含5,由函数isInclude5?实现;(3) 对于[0,x]中所有符合要求的数,get解决该问题。

(define (is3X? n)
    (= 0 (modulo n 3)))
注:没有%操作符,因为对于complex求余没有意义。参考R5RS,找到modulo 。

(define (isInclude5? n)
  (cond 	( (= 0 n) #f)
                ( (= 5 (modulo n 10)) #t)
                (else (isInclude5? (quotient n 10)) )))

注:递归吧

(define (p n)
   (begin (display n) (newline))
)

注:p这个是标准的助手方法

(define (get n)
(if 	(< 0 n)  
(begin 
(if  (and (is3X? n) ( isInclude5? n))
(p n) 
)
(get (- n 1)) )
(p "over")))

:这个写起来好麻烦。还是不习惯scheme。

关于递归,哼一句:大多数情况下,迭代法和递归法能够相互转化,即能用递归处理的算法可以采用迭代法,反之亦然。如果你愿意,Java的循环也可以全部采用递归。

Scheme,搞个for结构会咋样。

在必须递归情况下,憋的有点难受。

再假定待解决的问题为:输出0-x之间 3的倍数,而且含5并含7的数。编写一个单一方法就比较困难,而功能分解有助于问题的解决。

内部函数/块结构

对于用户而言,他仅仅关心get函数,而出于功能分解目的而得到的方法——称之为助手函数,在Java中常常设定为private方法。Scheme没有private这样的访问修饰符,而解决is3X?等函数名占用名称空间(用户可能也希望定义is3X?函数)、隐藏助手函数的手段是 内部函数——在函数内部定义的函数

(define (get n)
  (define (is3X? n)
    (= 0 (modulo n 3)))
  (define (isInclude5? n)
    (cond 	( (= 0 n) #f)
        ( (= 5 (modulo n 10)) #t)
       (else (isInclude5? (quotient n 10)) )))
  (define (p n)
    (begin (display n) (newline))
  ) 
(if 	(< 0 n)  
(begin 
(if  (and (is3X? n) ( isInclude5? n))
(p n) 
)
(get (- n 1)) )
(p "over")))
另外,get函数的参数n,它的作用域是整个get函数。对于助手函数如is3X?,如果get传递给is3X?的实参是n,则可以省略内部函数is3X?对应的形参名。在Java中,若干助手方法都需要使用的参数,通常提升为类的成员变量,不需要在助手方法中传来传去;Scheme的若干内部函数都需要使用的参数,可以提升为主函数的局部变量或形参。
注意:is3X?的参数可以省略,但是(p "over")说明它需要参数;而(isInclude5? n)说明了参数的可见性。


你可能感兴趣的:(Scheme之功能分解和封装内部函数/块结构)