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