Skip to content

Επιρροές συναρτησιακού προγραμματισμού σε κυρίως προστακτικές γλώσσες

  • Λάμδα συναρτήσεις (ανώνυμες συναρτήσεις)
  • Συναρτήσεις υψηλότερης τάξης (higher order functions)
  • Περιφραστικές λίστες (list comprehensions)
  • Μερικές συναρτήσεις (partial functions)
  • Οκνηρή αποτίμηση (lazy evaluation)
  • Κλειστότητες (closures)

Παραδείγματα απλών λάμδα συναρτήσεων σε C++, Java, Python

simple_lambda.cpp
#include <functional>
#include <iostream>

int main() {
  auto f = [](double x, double y) {
    return x * y;
  }; // δήλωση της λάμδα συνάρτησης και ανάθεσή της σε μεταβλητή
  std::cout << f(2, 21) << std::endl; // κλήση της λάμδα συνάρτησης

  std::cout << [](double x, double y) { return x * y; }(3, 21)
            << std::endl; // δήλωση και άμεση κλήση της λάμδα συνάρτησης
  return 0;
}
$ g++ simple_lambda.cpp -o simple_lambda
$ ./simple_lambda
42
63
SimpleLambda.java
package simple_lambda;
// 1 abstract function
interface MyFunctionalInterface {
    int fun(int x, int y);
}

class SimpleLambda {

    public static void main(String[] args) {
        MyFunctionalInterface f = (int x, int y) -> x * y;
        System.out.println(f.fun(2, 21));
    }
}
$ javac SimpleLambda.java 
$ java SimpleLambda
42
simple_lambda.py
1
2
3
4
f = lambda x, y: x * y  # δήλωση της λάμδα συνάρτησης και ανάθεσή της σε μεταβλητή
print(f(2, 21))  # κλήση της λάμδα συνάρτησης

print((lambda x, y: x * y)(3, 21))  # δήλωση και άμεση κλήση της λάμδα συνάρτησης
$ python simple_lambda.py
42
63

Notebook με παραδείγματα lambdas σε Python

Συναρτήσεις υψηλότερης τάξης σε C++, Java, Python

Ταξινόμηση λεκτικών με βάση το μήκος τους (χρησιμοποιείται ως παράμετρος ανώνυμη συνάρτηση)

sort_with_lambda.cpp
#include <algorithm>
#include <iostream>
#include <vector>

using namespace std;

int main() {
  vector<string> cities{"arta", "ioannina", "preveza", "igoumenitsa"};
  sort(cities.begin(), cities.end(),
       [](auto a, auto b) { return a.length() < b.length(); });
  for (auto city : cities) {
    cout << city << endl;
  }
}
$ g++ sort_with_lambda.cpp -o sort_with_lambda
$ ./sort_with_lambda
arta
preveza
ioannina
igoumenitsa
SortWithLambda.java
package sort_with_java;

import java.util.*;

public class SortWithLambda {
    public static void main(String[] args) {
        List<String> cities = new ArrayList<>(List.of("arta", "ioannina", "preveza", "igoumenitsa"));
        cities.sort((a, b) -> a.length() - b.length());
        for (String city : cities) {
            System.out.println(city);
        }
    }
}
$ javac SortWithLambda.java
$ java SortWithLambda
arta
preveza
ioannina
igoumenitsa
sort_with_lambda.py
1
2
3
4
5
cities = ["arta", "ioannina", "preveza", "igoumenitsa"]
cities.sort(key=lambda a: len(a))

for city in cities:
    print(city)
$ python sort_with_lambda.py
arta
preveza
ioannina
igoumenitsa

Περιφραστικές λίστες (list comprehensions) στην Python

Οι περιφραστικές λίστες είναι μια ιδέα που πρωτοεμφανίστηκε στην Haskell αλλά πλέον και άλλες γλώσσες όπως οι Scala, F# και Python έχουν ενσωματώσει τις περιφραστικές λίστες.

Notebook με παραδείγματα περιφραστικών λιστών στην Python

Μερικές συναρτήσεις στην Python

partial_function_example1.py
1
2
3
4
5
6
import functools
from operator import add

add5 = functools.partial(add, 5)

print(add5(15))
$ python partial_function_example1
20
partial_function_example2.py
import functools


def my_func4(a, b, c, d):
    return a + b + c + d


my_func3 = functools.partial(my_func4, 1)
my_func2 = functools.partial(my_func3, 2)
my_func1 = functools.partial(my_func2, 3)

print(my_func4(1, 2, 3, 4))
print(my_func3(2, 3, 4))
print(my_func2(3, 4))
print(my_func1(4))
$ python partial_function_example2
10
10
10
10

Οκνηρή αποτίμηση (lazy evaluation) στην Python

Στην Python, range είναι μια ακολουθία που δεν μπορεί να τροποποιηθεί (immutable) και η οποία αποτιμάται οκνηρά. Τα στοιχεία της ακολουθίας δεν δημιουργούνται παρά μόνο όταν απαιτούνται.

ranges_are_lazy.py
1
2
3
4
values = range(0, 1_000_000, 1000)
print(values)

print(values[5])
$ python ranges_are_lazy.py
range(0, 1000000, 1000)
5000
generators_are_lazy.py
# Δημιουργία "άπειρης" ακολουθίας Fibonacci με generator
def a_simple_generator():
    a = b = 1
    yield a
    yield b
    while True:
        yield a + b
        b += a
        a = b - a


gen = a_simple_generator()

for _ in range(20):
    print(next(gen))
$ python generators_are_lazy.py
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765

Notebook με παραδείγματα generators στην Python

Κλειστότητες στην Python

closure1.py
def outer_func():
    message = "Hi"

    def inner_function():
        print(message)  # free variable

    return inner_function()


outer_func()
$ python closure1.py
Hi
closure2.py
def outer_func():
    message = "Hi"

    def inner_function():
        print(message)  # free variable

    return inner_function  # αλλαγή σε σχέση με το closure1.py, επιστρέφει το όνομα της εμφωλευμένης συνάρτησης


my_func = outer_func()
my_func()
$ python closure2.py
Hi
closure3.py
def outer_func(msg):
    message = msg

    def inner_function():
        print(message)  # free variable

    return inner_function


hi_func = outer_func("Hi")
hello_func = outer_func("hello")

hi_func()
hello_func()
$ python closure3.py
Hi
Hello
closure4.py
import logging

logging.basicConfig(level=logging.INFO)


def logger(func):
    def log_func(*args):
        logging.info(f'Running "{func.__name__}" with arguments {args}')
        print(func(*args))

    return log_func


def add(x, y):
    return x + y


def sub(x, y):
    return x - y


add_logger = logger(add)
sub_logger = logger(sub)

add_logger(3, 3)
sub_logger(3, 3)
$ python closure4.py
INFO:root:Running "add" with arguments (3, 3)
6
INFO:root:Running "sub" with arguments (3, 3)
0