Functional programming is a very funny paradigm. On the one hand, everyone knows about it, and everyone likes to use all sorts of pattern matching and lambdas, on the other hand, few people usually write in a pure FP language. Therefore, the understanding that this is more likely to go back to myths and urban legends, which are very far from the truth, and people have the opinion that "FP is suitable for all fractal calculation programs that are divorced from life, and there is a proven track record for real tasks in battle time-tested OOP. "

Although people usually recognize the convenience of FP features, itβs much nicer to write:
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. " "/" "/"...", .
, , , . . "" , , . , β .