待解决的问题:输出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)说明了参数的可见性。