📜 ⬆️ ⬇️

"Patterns" of functional programming


Many people represent functional programming as something very complex and “high-tech”, and representatives of the FP community are aesthetic philosophers living in an ivory tower .

Until recently, such a view of things really was not far from the truth: we say OP, we mean Haskel and the theory of categories. Recently, the situation has changed and the functional paradigm is gaining momentum in web development, not without the help of F #, Scala and React. Let's try to look at the "patterns" of functional programming, useful for solving everyday tasks from the point of view of the PLO - paradigm.

OOP has been widespread in application software development for decades. We are all familiar with SOLID and GOF. What will be their functional equivalent? .. Functions! Functional programming is simply “different” and offers other solutions.
')


Basic principles of functional design (design)



Functions as first class objects


«» ( C++, C#, Java) - . : , (apple -> banana).

F# , :

let z = 1
let add = x + y // int -> int ->int


« »




, (apple -> banana), (banana -> cherry), (apple -> cherry). , – .

, . -, (use case) httpRequest -> httpResponse. , , .



. . control flow , , …
(Composite) «», , .

!=


, . int – . . Customer – . . int -> int – . «» — .

. , .

( «», record type F#)

, . , «» .

type Birthday = Person * Date

( «», discriminated union type F#)


type PaymentMethod =  
| Cash
| Cheque of ChequeNumber
| Card of CardType * CardNumber

Discriminated union – . . , , . , , .
«» .
Entity Framework , id.

«»




« 12 ». int -> int ! 0, . NonZeroInteger -> int int -> int option.



. . (Domain Model) - (Business Rules). , , , . .




, ( ). . ?



. , ( ).

let printList anAction aList =
    for i in aList do
        anAction i

. C#. , ( ). :

public static int Product(int n)
{     
    int product = 1; // 
    for (int i = 1; i <= n; i++) // 
    {
        product *= i; // 
    }

    return product; //  
} 
 
public static int Sum(int n) 
{
    int sum = 0; // 
    for (int i = 1; i <= n; i++) // 
    {
        sum += i;
    }

    return sum; //  
} 

F# fold:

let product n =
    let initialValue = 1
    let action productSoFar x = productSoFar * x

[1..n] |> List.fold action initialValue 
 
let sum n =
    let initialValue = 0
    let action sumSoFar x = sumSoFar+x

[1..n] |> List.fold action initialValue

, , C# Aggregate, ! , LINQ :)
C#. «» SelectMany


.

interface IBunchOfStuff
{
    int DoSomething(int x);
    string DoSomethingElse(int x); //   -  
    void DoAThirdThing(string x); //  
} 

SRP ISP .

interface IBunchOfStuff
{
    int DoSomething(int x);
} 

int -> int. F# , , « » . «» :

let DoSomethingWithStuff strategy x =
    strategy x

«»

let isEvenWithLogging = log >> isEven >> log  // int -> bool

. .


, . : . : .



, int -> int -> int . , int, int , int -> int. n, n — . .

, . , 1920- , — , .

, , .

let three = 1 + 2 
let three = (+) 1 2 
let three = ((+) 1) 2 
let add1 = (+) 1  
let three = add1 2 

. (Dependency Injection)

//    
let getCustomerFromDatabase connection (customerId:CustomerId) =
    from connection
    select customer
    where customerId = customerId
 
//    
let getCustomer1 = getCustomerFromDatabase myConnection 

(continuations)


, , . . , , ? « »

int Divide(int top, int bottom) 
{
    if (bottom == 0)
    {
        //  ,    ?
        throw new InvalidOperationException("div by 0");
    }
    else 
    {
        return top/bottom;
    }
}

, , :

void Divide(int top, int bottom, Action ifZero, Action<int> ifSuccess) 
{
    if (bottom == 0)
    {
        ifZero();
    }
    else
    {
        ifSuccess( top/bottom );
     }
}
 

- , « » (Pyramid Of Doom)



. :

let ifSomeDo f opt =
    if opt.IsSome then
        f opt.Value
    else
        None

,

let example input =
    doSomething input
    |> ifSomeDo doSomethingElse
    |> ifSomeDo doAThirdThing
    |> ifSomeDo (fun z -> Some z)


– «» . , - , . — - «» — , . « ». .



«», . , «» .

:(




bind



let bind nextFunction optionInput =
    match optionInput with
    //        
    | Some s -> nextFunction s
    //     None 
    | None -> None

bind

// 
let example input =
    let x = doSomething input
    if x.IsSome then
        let y = doSomethingElse (x.Value)
        if y.IsSome then
            let z = doAThirdThing (y.Value)
            if z.IsSome then
                let result = z.Value
                Some result
            else
               None
        else 
            None 
    else
        None 

// 
let bind f opt =
    match opt with
        | Some v -> f v
        | None -> None

let example input =
    doSomething input
        |> bind doSomethingElse
        |> bind doAThirdThing
        |> bind (fun z -> Some z)

, «monadic bind». , , , «monadic bind» :)

Bind ( JS )



Bind


, Either,

C#. : . . , ?

string UpdateCustomerWithErrorHandling() 
{
    var request = receiveRequest();
    validateRequest(request);
    canonicalizeEmail(request);
    db.updateDbFromRequest(request);
    smtpServer.sendEmail(request.Email) 
    return "OK";
} 

, . .

string UpdateCustomerWithErrorHandling() 
{
    var request = receiveRequest();
    var isValidated = validateRequest(request);
    if (!isValidated) 
    {
        return "Request is not valid"
    }
    
    canonicalizeEmail(request);
    try 
    {
         var result = db.updateDbFromRequest(request);
         if (!result) 
        {
           return "Customer record not found"
        }
    }
    catch
    {
        return "DB error: Customer record not updated"
    } 
 
    if (!smtpServer.sendEmail(request.Email))
    {
        log.Error "Customer email not sent"
    } 
 
    return "OK";
} 

18 . 200% . , .

bind . , F#:

:


.


. «, »


, . .

, ,





?


  1. , , . — ().
  2. ().
  3. , , ( ).

. .




1 * 2 * 3 * 4
[ 1; 2; 3; 4 ] |> List.reduce (*)


« », «» . 2 1 + 2 + 3 + 4. 1 + 2 , 3 + 4 — , . — .


reduce : ? , ? , .
, . , , .

Map / Reduce


— , . Google — .




— «» ( ). , , .
, Event Sourcing — . Flux unidirectional data flow, .


VS


, , — , — .
, — GOF . «» — .

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


All Articles