Funktionale Programmierung ist ein sehr lustiges Paradigma. Einerseits weiß jeder Bescheid, und jeder benutzt gerne alle Arten von Pattern Matching und Lambdas, andererseits schreiben nur wenige Leute normalerweise in einer reinen FP-Sprache. Daher ist das Verständnis, dass dies eher auf Mythen und urbane Legenden zurückgeht, die sehr weit von der Wahrheit entfernt sind, und die Menschen sind der Meinung, dass "FP für alle fraktalen Berechnungsprogramme geeignet ist, die vom Leben getrennt sind, und es gibt eine nachgewiesene Erfolgsbilanz für echte Aufgaben im Kampf erprobte OOP. "

Obwohl die Leute normalerweise den Komfort von FP-Funktionen erkennen, ist es viel angenehmer, Folgendes zu schreiben:
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. " "/" "/"...", .
, , , . . "" , , . , — .