Java程序辅导

C C++ Java Python Processing编程在线培训 程序编写 软件开发 视频讲解

客服在线QQ:2653320439 微信:ittutor Email:itutor@qq.com
wx: cjtutor
QQ: 2653320439
Functional versus Imperative
Hans Georg Schaathun
November 5, 2008
These notes will be (were) discussed Friday 31 October, at the start of the lecture.
They are prepared in response to a series of questions and problems arising in the lab
sessions.
1 Java vs. Haskell
1. What is the difference between (programming in) Java and Haskell?
2. What is the similarity between (programming in) Java and Haskell?
Haskell isn't real programming like Java; it is like using interactive software
such as a calculator.
The hugs interpreter provides a simple tool to test components of new programs. You
should look at the programming that we do as the creation of small building blocks which
are not assembled yet.
It is a disadvantage of compiled programming languages that testing becomes hard.
In order to test the basic building blocks, you have to create separate programs for each
function to be tested. These programs have no user value. When we have an interactive
interpreter (hugs), testing is simpler. You can evaluate any function, on the command
line, without the creation of a complete program.
1.1 Large programs
The purpose of University modules is not to teach particular languages, but to teach
universal programming techniques which can be used in software development. Large
systems will employ more than one technique.
Real software systems are composed of many different modules doing different tasks.
There will be
• I/O functions communicating with the user
• Computational functions, calculating information required from data stored
1
• Data processing functions (sorting, searching)
• I/O functions reading and storing data on disk
Your java module has started with user oriented I/O. Imperative languages are good
and easy to use for I/O, so this makes sense. Furthermore, since you don't have an
interactive interpreter, you need I/O to be able to verify that the function or program
works as intended.
In this module, we have started with computational functions. The interpreter allows
us to test and debug these functions, without learning to do I/O. Functional programming
techniques are very efficient and practical for this kind of computations, and they produce
very readable code. I/O on the other hand, is hard to do in functional languages.
In the future, when you start creating complex systems, you will see that techniques
from your Java module applies to Haskell, and vice versa. You will need different tech-
niques for different parts of the system, and put it all together.
2 Modules
The test script for Coursework 1 has introduced the concept of modules. You do not
need to know anything about modules yet, but since you have seen them in operation, I
shall explain it.
Modules roughly correspond to (abstract) classes in Java. They are collections of
functions which can be imported in other programs or modules.
In hugs, you are allowed to load Haskell files which do not explicitely declare a module.
In these cases, hugs will treat the file as a module called Main. However, such files cannot
be imported by other modules or Haskell files.
In order (explicitely) to declare a module, you simply need a line of the following form.
• module Ex2 where
The file name (Ex2.hs) has to match the module name (Ex2). When the module is
explicitely declared, it can be included in another file. My test script for Coursework 1
has the line import Ex2 to import your file.
3 The Coursework 1 Test Program
The test program for Coursework 1 is a standalone program. It can be run by the
command
• runhugs test2
directly in the terminal window. The runhugs program is a non-interactive version of
the hugs interpreter. It does not give you a prompt, instead it runs the Haskell program
from the given file.
It is also possible to compile the test2.hs program using the Glasgow Haskell Compiler
(ghc). We shall have a look at this in Week 7.
My test script is a standalone program because it
2
int factorial ( int n ) {
int i, r=1 ;
for ( i=1 ; i <= n ; ++i ) {
r = r*i ;
}
return ( r ) ;
}
Figure 1: A factorial function using loops in C/Java.
int factorial ( int n ) {
int r=1 ;
for ( ; n > 1 ; --n ) {
r = r*n ;
}
return ( r ) ;
}
Figure 2: A factorial function using loops in C/Java, counting down. This avoids the
extra variable i needed when the loop is counting up.
1. Declares a module called Main.
2. Includes a function called main.
All that runhugs does is to load the module and evaluate main.
4 Recursion vs. Loops
Recursion is the single most important topic in this module. As you have now learnt the
for loop in Java, it may be useful to compare loops and recursion.
• How would you create a factorial function in Java?
int factorial ( int n ) {
if ( n <= 1 ) {
return (1)
} else {
return ( n*factorial(n-1) ) ;
}
}
Figure 3: A factorial function using recursion in C/Java.
3
factorial :: Int -> Int
factorial n
| n <= 1 = 1
| otherwise = n*(factorial (n-1))
}
Figure 4: A factorial function using recursion in Haskell.
Figures 1 and 2 shows two ways of doing this using loops, making one multiplication
at each step.
Loops is an imperative technique which is not available in functional languages. At
the heart of the for loop is the index variable (i in Figure 1) which is updated for
each iteration. This variable creates a variable state, and the expression r = r*i is not
transparent; it depends on the state of the machine. Haskell requires that any expression
takes the same value every time it is evaluated.
Recursion can be used in Java. Figure 3 shows a recursive C/Java function to calculate
the factorial. This is a purely functional approach, with referential transparency. Inside
the scope of the function, n is constant (given as an argument). There are no variables
which are updated. Two calls of factorial(n) would always give the same answer
(independent of state).
This example illustrates that functional techniques applies in Java. In this simple
example there is little practical difference between loop and recursion. Both are readable
and efficient. In more complex examples, one or the other may be better.
Returning to the Haskell code in Figure 4, we see an almost perfect match between
the syntaxes of Java/C and of Haskell.
4