Можете ли вы представить один и тот же пример, используя процедурные, функциональные, логические и ОО языки программирования? - PullRequest
12 голосов
/ 29 сентября 2011

Может ли кто-нибудь предоставить мне пример, который может помочь мне понять процедурные, функциональные, логические и объектно-ориентированные модели программирования бок о бок, используя почти такую ​​же примерную проблему.

Пожалуйста, дайте мне примеры фрагментов кода той же проблемы с использованием процедурных, функциональных, логических и ОО языков программирования.

Ответы [ 4 ]

11 голосов
/ 29 сентября 2011

http://99 -bottles-of-beer.net /

(Это мой собственный ужасно надуманный 99 язык.)

10 голосов
/ 18 ноября 2011

Давайте попробуем более простой пример - просто вычисление n-го числа Фибоначчи.

Во-первых, процедурный (в Паскале):

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.

В этом примере показаны особенности процедурных языков:

  • Есть некоторые подпрограммы (функция в данном случае)
  • Переменным присваивается значение, вероятно, несколько раз (: = оператор)
  • Есть циклы ( для оператора в данном случае)
  • Язык является обязательным, то есть мы говорим компьютеру, что делать в каком порядке

Во-вторых, объектно-ориентированный (в Python):

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)

На самом деле проблема не стоит создавать класс, поэтому я добавил кеширование уже рассчитанных результатов.

В этом примере показано:

  • class иего экземпляр (создание экземпляра)
  • класс имеет собственный раздел памяти, собственное состояние ( self и его члены)
  • Язык является обязательным, то есть мы говорим компьютеру, чтоделать в каком порядке

Не показано, но мы cНапример, потомок этого класса из абстрактного класса, возвращающий 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 "%d\n" (fib 6)

Показаны следующие особенности парадигмы функционального программирования:

  • нет состояния, нет переменных - только определенные функции
  • нет циклов - только рекурсия
  • сопоставление с образцом: мы отдельно определили «fib 0», «fib 1» и «fib n» для остальных чисел, без конструкций, подобных , если было необходимо
  • декларативностиль - мы не определяем порядок шагов для вычисления основного значения функции: компилятор / интерпретатор / среда выполнения вычисляет это самостоятельно, учитывая определения функций.Мы сообщаем компьютеру, что мы хотим получить, а не что делать.
  • Ленивая оценка.Если main вызывал только «fib 2», то «fib n» не вызывался, потому что функции оцениваются только тогда, когда их результат необходимо передать в качестве параметра другим функциям.

Но главная особенностьФункциональные языки - это то, что функции являются объектами первого класса.Это можно продемонстрировать с помощью другой реализации fib:

fib n = fibs!!n
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

Здесь мы передаем функцию fibs в качестве параметра функции zipWith.Этот пример также демонстрирует ленивую оценку: «бесконечный» список вычисляется только в той степени, в которой он необходим для других функций.

Кстати, функционал не обязательно означает не объектно-ориентированный.Примером языка программирования, который является одновременно функциональным и объектно-ориентированным, является Scala.

Пролог:

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-1-го числа Фибоначчи и X-2-го числа Фибоначчи), Пролог выводит предикаты, о которых идет речь.На самом деле может быть более 1 ответа!
  • Нет входных значений и возвращаемого значения - вместо этого мы определяем соотношение между «входом» и «выходом».

Эту программу также можно использовать для определения того, что число 8 Фибоначчи находится на 6-й позиции в последовательности:

?- between(0,inf,X), fib(X,8).
X = 6 .
7 голосов
/ 15 ноября 2011

Проект Эйлера Задача № 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("%d\n", sum);
}

А вот очень неэффективная версия, написанная на схеме MIT

(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.
1 голос
/ 09 ноября 2014

Ну, это очень просто

  1. процедурная, функциональная логика Допустим, вы хотите что-то вычислить (это то, что делают компьютеры)
    1. разбить проблему на функции, скажем, f1, f2, f3 .... теперь, если вы посмотрите на проблему, вы увидите, что она разделена на функции .. но должна быть начальная точка (с которой вы начинаете вычисления) и конечная точка (где вы заканчиваете вычисления), и между ними находятся функции (f1 , f2, f3). Таким образом, то, что вы действительно сделали, это вместо того, чтобы писать одну большую функцию (F), которая выполняет все и очень долго, вы разбиваете ее на более мелкие части (это называется рефакторингом). Понимать одну функцию длиной 150 строк скучно ... когда вы доберетесь до конца строки, вы забудете, с чего начали, и мы разберемся. Теперь, как мы делаем вычисления ---> Мы создаем единственную функцию, скажем, compute () (это называется фасадом), которая будет вызывать остальные функции (f1, f2, f3 ...) в нужном порядке и будет возвращать результат. Теперь поймите это: Если бы мы написали одну функцию, это было бы около 150 строк (сложность увеличивается). Предположим, мы разбили его на 3 функции и скажем, что каждая функция состоит из 50 строк (управляемых). Как мы уменьшили сложность, поскольку сумма строк из 3 функций все еще равна 150: D. сложность уменьшается на имя функции ... которая четко указывает, что делает функция ... это означает, что, глядя на имя, вы можете понять, что делает функция.

OO Логика программирования:
Теперь функции разбросаны по функциональной логике ... когда мы объединяем все связанные функции (поведение) в одном зонтике (классе), мы еще больше снижаем сложность ... как .. "именем класса". Теперь вы можете сказать, что вместо вызова f1, f2, f3 .. мы вызываем c1.f1 (), c2.f2, c3.f3 (), где «c» обозначает класс (проект, управляемый доменом).

imp .. независимо от того, используете ли вы упс или функциональную логику, всегда есть начальная и конечная точка вычислений ... запомните compute (), о которой я говорил ... и вопрос в том, кто это называет ... и ответ это ты .. Вся логика или процедурная логика ООП скрыта за ней (Service Facade)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...