La programmation fonctionnelle n'est pas ce qu'on nous dit

La programmation fonctionnelle est un paradigme très amusant. D'une part, tout le monde le sait et tout le monde aime utiliser toutes sortes de correspondances de motifs et de lambdas, d'autre part, peu de gens écrivent généralement dans un langage de PF pur. Par conséquent, la compréhension que cela est plus susceptible de revenir aux mythes et aux légendes urbaines, qui sont très loin de la vérité, et les gens pensent que "la PF convient à tous les programmes de calcul fractal qui sont dissociés de la vie, et il existe des antécédents éprouvés pour des tâches réelles dans la bataille OOP éprouvée. "



Bien que les gens reconnaissent généralement la commodité des fonctionnalités FP, il est beaucoup plus agréable d'écrire:


int Factorial(int n)
{
    Log.Info($"Computing factorial of {n}");
    return Enumerable.Range(1, n).Aggregate((x, y) => x * y);
}


int Factorial(int n)
{
    int result = 1;
    for (int i = 2; i <= n; i++)
    {
        result *= i;
    }
    return result;
}

? . .


, ? , , — ? , , .


, ? , , . :


— , .

, , ? — , . , :


f f(x) x

, " ". — , ? ? " " ? , , , .


? :


— ,

- var x = foo() var x = result_of_foo . . ( ) . — , " ". , . , CPU — ( , ). — !


. , ? , , - Factorial(5) 120 — ( " , " , . , , , ).


? : .


, , var x = result_of_foo var x = foo() . "Equational reasoning", " ". , — , .


: . , . ST, . — : ST . , , , — .



— . ? , ST ( ) , … — . goto , , goto , - .


Equational reasoning , : . , , , .


. C#, , ( )


var something = function();
DoStuff(this.Field, something);

, :


DoStuff(this.Field, function());

, , . , function :


... - 
this.Field = GetUpdatedVersion(this.Field, localData) // ! 
...     

:


var something = function();
var arg1 = this.Field;      //   function -  !
var arg2 = something;
DoStuff(arg1, arg2);

:


var arg1 = this.Field;      //   function -   !
var arg2 = function();
DoStuff(arg1, arg2);

DoStuff , .


? " , "? , , . .


, , . , , - C# , , DI , function DoStuff, . , , .


. , . , - . , . , , . , . , , , . , — . — , - .



, Scala ( , , c ). , C#.


, . , .



, , :


public class Cafe
{
    public Coffee BuyCoffee(CreditCard card)
    {
        var cup = new Coffee()
        card.Charge(cup.Price)
        return cup
    }
}

card.Charge(cup.Price) . — , - - -, . , Coffee, "" " ".


- . " !". , :


public class Cafe
{
    public Coffee BuyCoffee(CreditCard card, IPaymentProvider paymentProvider)
    {
        var cup = new Coffee()
        paymentProvider.Charge(card, cup.Price)
        return cup
    }
}

: IPaymentProvider. .


  • - IPaymentProvider, .
  • - . — InMemory DB, Insert/Save/… , ( ) , . , — ? , - , , .
  • - . N . ( ):

public class Cafe
{
    public Coffee BuyCoffee(CreditCard card, IPaymentProvider paymentProvider)
    {
        var cup = new Coffee()
        paymentProvider.Charge(card, cup.Price)
        return cup
    }

    public Coffee[] BuyCoffees(int count, CreditCard card, IPaymentProvider paymentProvider)
    {
        //      0   , 
        //       0 
        if (count == 0) return Array.Empty<Coffee>(); 
        var cups = Enumerable.Range(0, count).Select(_ => new Coffee()).ToArray();
        paymentProvider.Charge(card, cups[0].Price * count)
        return cups
    }
}

. - , .



, ? — , , . :


public class Cafe
{
    public (Coffee, Charge) BuyCoffee(CreditCard card)
    {
        var cup = new Coffee()
        return (cup, new Charge(card, cup.Price))
    }
}

, . , , . , Charge . : . Charge DTO . , . , . , . , !


N ? , N BuyCoffee , .


public class Cafe
{
    public (Coffee, Charge) BuyCoffee(CreditCard card)
    {
        var cup = new Coffee()
        return (cup, new Charge(card, cup.Price))
    }

    public (Coffee[], Charge) BuyCoffees(int count, CreditCard card)
    {
        var (coffees, charges) = Enumerable.Range(0, count)
                                           .Select(_ => BuyCoffee(card))
                                           .Unzip();
        return (coffees, charges.Aggregate((c1, c2) => c1.ombine(c2))
    }
}

- Combine:


public class Charge
{
    public CreditCard Card { get; set; }
    public double Amount { get; set; }

    public Charge(CreditCard card, double amount)
    {
        Card = card;
        Amount = amount;
    }

    public Charge Combine(Charge other)
    {
        if (Card != other.Card) 
            throw new ArgumentException("Can't combine charges to different cards");
        return new Charge(Card, Amount + other.Amount);
    }
}

- . , , :


IEnumerable<Charge> Coalesce(IEnumerable<Charge> charges) => 
    charges.GroupBy(x => x.Card).Select(g => g.Aggregate((c1, c2) => c1.Combine(c2))

, . , , , .


, , - , , , - Cafe. , , , , , - ( , ).


, IPaymentProvider , , : , , , "" , , . , , .


, , . " " , . RAII: , .


?


— , . , , . , , , . ( int ) , (, goto) , (Templates vs Generics) , .


, , . , "" , , , . ? void UpdateOrders() void UpdateUsers() () -> (), . () -> OrdersUpdate () -> UsersUpdate. , ( ) , .


? , ( Rust)


//   ,  - ,      
fn foo<T>(a: &[T], b: T) -> T { ...- ... }

, , , — b . ? , T. . , — .



let a = [1,2,3,4,5];
let b = foo(a, 10);
assert!(b == 10 || a.iter().any(|x| x == b))

, UB - ( ). , , - - , (, , ).


:


fn foo<T>(a: &[T]) -> T { ...- ... }

, , , - . , , Bottom- ⊥. ? T, . a. -, . .


, , .


, ? , . , :


T Foo<T>(List<T> list, T value) => default(T);

, . . , , — . , , , .


, T? :


fn foo<T: Default>(a: &[T]) -> T { ...- ... }

, , . , , - . — . . ! , default(T).


99% , . , . Haskell Hoogle . .


(a -> Bool) -> [a] -> [a] (, : , ) filter takeWhile.


. , ? , .


fn bar<T>(s: String) -> T { ... } // -
bar :: String -> a                // -

, , . , — . , ⊥. , . , , :


fn bar<T>(s: String) -> T { 
    panic!(s);
}

— ( ), . , . , , , .


, , , . foo 1000 , , . . 1000 . .


- ?


, . "", , " , HTTP , . . ".


, , . ", . , ( )? , , !".


? IO, . , Charge , /. IO , print "Hello world" . main = print "Hello world" . ?


, IO. main. , . "" — , , , . .


, , . main , .


, , — , . , . "", . .


, , . Rust:


fn main() {
    let _ = print!("Hello ");
    println!("world!");
}

"Hello world!". Haskell:


main :: IO ()
main = do
  let _ = print "Hello "
  print "world!"

"world!". . " Hello", . . main world!, . Rust print! , - .


( , - ) , . " " . , " ( ), HTTP ( , ), . , .



, . , , . , . - ANSI C , . . , Scala Haskell — . , , , , . , .


. , - . DI. " "/" "/"...", .


, , , . . "" , , . , — .

Source: https://habr.com/ru/post/fr479238/


All Articles