البرمجة الوظيفية هي نموذج مضحك للغاية. من ناحية ، يعرف الجميع عن ذلك ، والجميع يحب استخدام جميع أنواع مطابقة الأنماط و lambdas ، من ناحية أخرى ، عادة ما يكتب عدد قليل من الناس بلغة FP خالصة. لذلك ، فإن فهم أن هذا من المرجح أن يعود إلى الأساطير والأساطير الحضرية ، التي هي بعيدة كل البعد عن الحقيقة ، ويرى الناس أن "FP مناسب لجميع برامج حسابية كسورية منفصلة عن الحياة ، وهناك سجل حافل للمهام الحقيقية في معركة اختبارها OOP ".

على الرغم من أن الأشخاص عادةً ما يتعرفون على مزايا ميزات FP ، إلا أنه من الأفضل أن تكتب:
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. " "/" "/"...", .
, , , . . "" , , . , — .