谁能给我提供一个例子,可以帮助我理解过程,功能,逻辑和面向对象的编程模型并排使用几乎相同的例子问题。
请给我的例子代码片段有些相同的问题使用过程,函数,逻辑和OO编程语言。
让我们尝试一个更简单的例子-只是计算n个斐波那契数。
首先是过程的(在Pascal中):
program Fibonacci;
function fib(n: Integer): Integer;
var a: Integer = 1;
b: Integer = 1;
f: Integer;
i: Integer;
begin
if (n = 1) or (n = 2) then
fib := 1
else
begin
for i := 3 to n do
begin
f := a + b;
b := a;
a := f;
end;
fib := f;
end;
end;
begin
WriteLn(fib(6));
end.
这个例子展示了过程语言的特性:
- 有一些子程序(在这种情况下是函数)
- 变量可能被赋值多次(:= operator)
- 有循环(对于操作符在这种情况下)
- 语言是命令式的,即我们告诉计算机以什么顺序做什么
class Fibonacci:
def __init__(self):
self.cache = {}
def fib(self, n):
if self.cache.has_key(n):
return self.cache[n]
if n == 1 or n == 2:
return 1
else:
a = 1
b = 1
for i in range(2, n):
f = a + b;
b = a;
a = f;
self.cache[n] = f;
return f;
fibonaccyCounter = Fibonacci()
print fibonaccyCounter.fib(6)
实际上这个问题不值得创建一个类,所以我添加了已经计算结果的缓存。
这个例子显示了:
- 类及其实例化(创建实例)
- 类有自己的内存段,自己的状态(self及其成员)
- 语言是命令式的,即我们告诉计算机以什么顺序做什么
没有显示,但是我们可以从返回某个序列的第n个成员的抽象类派生出这个类。通过子类化,我们得到了定义斐波那契数列的类,数列1,2,3…,数列1、4、9、16、…等。
第三,函数式风格(Haskell):import Text.Printf
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
main = printf "%dn" (fib 6)
函数式编程范型的以下特性被演示:
- 没有状态,没有变量,只有定义的函数
- 没有循环-只有递归
- 模式匹配:我们为其余的数字分别定义了"fib 0","fib 1"one_answers"fib n",如果需要,则不需要像这样的结构
- 声明式风格-我们不定义计算main函数值的步骤顺序:编译器/解释器/运行时根据函数定义自行计算。我们告诉计算机我们想得到什么,而不是做什么。
- 懒惰的评价。如果main只调用了"fib 2",那么"fib n"就不会被调用,因为函数只有在需要将其结果作为参数传递给其他函数时才会被求值。
但是函数式语言的主要特点是函数是第一类对象。这可以通过fib
的其他实现来证明:
fib n = fibs!!n
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
这里我们将fibs
函数作为参数传递给zipWith
函数。这个例子还演示了延迟求值:"infinite"列表只在其他函数需要的范围内计算。
序言:
fib(1, 1).
fib(2, 1).
fib(X, Y):-
X > 1,
X1 is X - 1,
X2 is X - 2,
fib(X1, Z),
fib(X2, W),
Y is W + Z.
main :-
fib(6,X), write(X), nl.
可以看到逻辑编程风格的以下特征:
- 语言是声明性的。在函数式风格中,我们定义事物,而不是告诉它们以什么顺序执行。
- 但是函数式风格的不同之处在于我们定义谓词,而不是函数。在这种情况下,谓词fib(X, Y)表示"第X个斐波那契数是Y"。给定一些已知的谓词(fib(1,1)和fib(2,1) -即第一个斐波那契数为1,第二个斐波那契数为1)和推断其他谓词的规则(Y是x -第一个斐波那契数,Y是x -第一个斐波那契数和x -第2个斐波那契数的和),Prolog推断出问题中的谓词。实际上答案可能不止一个!
- 没有输入值和返回值——取而代之的是我们定义了"输入"one_answers"输出"之间的关系。
这个程序也可以用来找出斐波那契数字8在序列中的第6位:
?- between(0,inf,X), fib(X,8).
X = 6 .
(它使用了我自己可怕的99语言)
欧拉项目问题2:http://projecteuler.net/problem=2
Haskell(功能/逻辑):
p2 = sum [x | x <- fibs, (x `mod` 2) == 0] where
fibs = unfoldr acc (0,1) where
acc (prev, cur) | (prev+cur) > 4000000 = Nothing
| otherwise = Just (prev+cur, (cur, prev+cur))
Python (OO): class FibSum(object):
def __init__(self, end):
self.end = end
self.next_two = (1,0)
self.sum = 0
def __iter__(self):
return self
def next(self):
current, previous = self.next_two
self.next_two = (previous+current, current)
new = current+previous
if current >= self.end:
raise StopIteration
elif (new % 2) == 0:
self.sum += new
else:
pass
fibcount = FibSum(4000000)
[i for i in fibcount]
print fibcount.sum
C(程序/命令):
#include <stdio.h>
int main(void)
{
long int sum, newnum, previous = 0;
long int current = 1;
while(current <= 4000000)
{
newnum = previous+current;
if ((newnum % 2) == 0)
{
sum = sum + newnum;
}
previous = current;
current = newnum;
}
printf("%dn", sum);
}
这是一个非常低效的MIT Scheme版本
(define (unfold func seed)
(let* ((result (func seed)))
(cond ((null? result) ())
(else (cons (car result) (unfold func (second result)))))))
(define (test x)
(cond ((> (sum x) 4000000) ())
(else (list (sum x) (list (second x) (sum x))))))
(define (sum xs)
(cond ((null? (cdr xs)) (first xs))
(else (+ (car xs) (sum (cdr xs))))))
(sum (filter (lambda (x) (eq? (modulo x 2) 0)) (unfold test (list 0 1))))
序言:从这里,由13tazer31张贴
fibonacci(_,Current,End,0) :-
Current > End.
fibonacci(Previous, Current, End, Total) :-
divisible(Current, 2),
Next is Current + Previous,
fibonacci(Current, Next, End, Sum),
Total is Sum + Current, !.
fibonacci(Previous, Current, End, Total) :-
Next is Current + Previous,
fibonacci(Current, Next, End, Total).
divisible(Number, 0) :-
write(‘Error: division by 0′).
divisible(Number, Divisor) :-
Number mod Divisor =:= 0.
这很简单
- 程序、功能逻辑假设你想计算一些东西(这就是计算机的工作)
- 将问题分解为f1,f2,f3....现在如果你看一下这个问题,你会发现它被分成了几个函数。但是必须有一个起点(开始计算的地方)和一个终点(结束计算的地方)它们之间是函数(f1,f2,f3)因此,你真正做的不是写一个大函数(F),它做所有的事情,而且很长,而是把它分成更小的部分(这被称为重构)。理解一个150行长的函数是很无聊的。当你到达终点时,你会忘记你从哪里开始,所以我们把事情分开。现在我们如何计算——>我们创建一个函数compute()(这被称为facade),它将以所需的顺序调用剩余的函数(f1、f2、f3…)并返回结果。现在你要明白:如果我们只写一个函数,那大概有150行(复杂性增加了)。假设我们将其分解为3个函数,每个函数有50行(可管理)。既然三个函数的行和仍然是150:D,我们如何降低复杂性?通过函数名降低了复杂度。它清楚地说明了函数的作用……这意味着看名字你就能知道这个函数是做什么的。
OO编程逻辑:
函数在函数逻辑中是分散的。当我们把所有相关的函数(行为)放在一个保护伞(类)中时,我们进一步降低了复杂性。如何. .按"类名"。现在你可以说,不调用f1 f2 f3。我们调用c1.f1(),c2.f2,c3.f3(),其中"c"表示一个类(领域驱动设计)。
imp . .无论你是使用oop还是函数逻辑,计算总是有一个开始和结束点…还记得我说过的计算机吗?问题是谁叫它…答案是你…所有OOP的逻辑或过程逻辑都隐藏在它后面(Service Facade)