يحب أتباع البرمجة الوظيفية إغراء الوافدين الجدد بوعود بالتعبير التام عن الكود ، وصحة 100٪ ، وسهولة الدعم وسهولة إعادة البناء ، وحتى في بعض الأحيان التنبؤ بأعلى أداء. ومع ذلك ، فإن المطورين ذوي الخبرة يعرفون أن هذا لا يحدث. البرمجة هي عمل شاق ، و "حبوب سحرية" غير موجودة.
من ناحية أخرى ، فإن عناصر من أسلوب البرمجة الوظيفية قد اخترقت بالفعل لغات البرمجة الصناعية مثل Swift و Kotlin. مطورو هذه اللغات على دراية جيدة بالبرمجة الوظيفية ، لذلك كانوا قادرين على استخدامها "بشكل صغير" ، وتوفير العديد من المكونات الضرورية ، إن لم يكن كلها. الأبعد - يتم إدخال المزيد من أجزاء FI في الأسلحة النووية الصناعية ، ويتم تنفيذ الدعم بشكل أفضل وأكمل.
أن تكون قادرًا على البرمجة بأسلوب وظيفي مفيد في تبسيط عملك ، والآن سنرى كيفية استخدامه!
Vitaliy Bragilevsky هو مدرس في FP ، ونظرية الخوارزميات والحساب ، ومؤلف كتاب "Haskell in Depth" وعضو في لجان Haskell 2020 ولجنة الإشراف على مترجم GHC.
تاريخ موجز
قصص البرمجة الوظيفية ليست دائما صحيحة. كثيرا ما يتحدث الناس عن AF مثل هذا.
"ذات مرة في مجرة بعيدة بعيدة ، كانت البرمجة بسيطة ومباشرة وجيدة. تتم برمجة الخوارزميات وهياكل البيانات وكل شيء على ما يرام - لا توجد مشاكل!
ثم جاء مخيفو Sith الذين قرروا أن جميع البرامج تتكون من فصول: "البرمجة الموجهة للكائنات للجميع! كل شيء يحتاج إلى أن يكتب فقط بهذه الأساليب.
عندما اكتسبوا القوة ، أصبح من المستحيل تطوير البرامج - ظهرت الكثير من المشكلات. لإنقاذ المطورين الذين يعانون من سوء الحظ ، وهناك برمجة وظيفية. "الشيء الرئيسي في الخلاص هو رسم صورة جميلة لا معنى لها.

عندما تقوم بتطبيق كل شيء في الصورة ، ستأتي السعادة والسلام والهدوء ، وسيتم حل مشاكل تطوير البرامج.
القصة جميلة ، ولكن في الواقع كل شيء مختلف. هذه هي الطريقة التي أمثل بها البرمجة الوظيفية والصناعية.

البرمجة الوظيفية هي مختبر فاراداي - مهد الأفكار التي يتم تطبيقها بعد ذلك في البرمجة الصناعية.
في محادثة حول لغات البرمجة الصناعية ، لا ينبغي أن تثار مفاهيم ما إذا كانت تعمل أم لا ، سواء كانت تستخدم FP أو لا ،!
المهمة الرئيسية لل FP هي نقل العناصر الجيدة إلى اللغات السائدة.
إن الرغبة في نقل الجميع إلى قضبان وظيفية هي نفس إجبار العلماء على إجراء تجارب مثل فاراداي - هذا لا معنى له. لا أحد يجري حاليا تجارب على الكهرباء بهذه الطرق العتيقة.
لنلقِ نظرة على الأمثلة.
جون مكارثي وظيفة
جون مكارثي هو واحد من المبدعين من Lisp.

كانت فورتران لغة البرمجة الرئيسية قبل 65 عامًا. يحتوي على بيان شرطي:
IF (I.NE.0) GOTO 40
STMT-1
STMT-2
40 STMT-3
I 0, «40».
, , . ,
XIF(M, N1,N2)
, , : N1 N2.
: «… » , .
— N1 N2. , ?
:
M==0 ? N1 : N2
. . , , - .
?
— . 1977 . « ?». — — , .

— , .
- :
c := 0
for i := 1 step 1 until n do
c := c + a[i]*b[i]
— .
. FP.
Def DotP = (Insert +) o (ApplyToAll x) o Transpose
—
o
, , , .
— — , , .
. .
, - Java . , , , .

, , :
, .
:
fun countLinesInFiles(fnames: List<String>): Int
= fnames.map { File(it).readLines().size }
.sum()
Kotlin, , . ?
, , .
— «map» — .
, : , . it — . — sum().
,
map
Kotlin, , . , . —
readLines
.
Haskell
, Haskell.
countLines :: FilePath -> IO Int
countLines = fmap (length . lines) . readFile
countLinesInFiles :: [FilePath] -> IO Int
countLinesInFiles = fmap sum . traverse countLines
, , . Haskell , , .
. , : , Int — .
. «IO», Haskell ,
-. « », Int, IO Int. , .
. — Haskell. — FilePath, IO Int — . : , traverse — , «countLines».
. «. » (
o
) — . , .
«f. g» — , «x» «f(g(x))». , . , . .
.
, , . — , .
UML-. : , , , , .

Swift
, , - . Swift , , .
protocol Shape {
func area() -> Double
func diameter() -> Double
}
class Circle: Shape {
var r = 0.0
init(radius: Double) {
r = radius
}
func area() -> Double {
return 3.14 * r * r
}
func diameter() -> Double {
return 2 * r
}
}
class Square: Shape {
var s = 0.0
init(size: Double) {
s = size
}
func area() -> Double {
return s * s
}
func diameter() -> Double {
return sqrt(2) * s
}
}
, .
: , , – , . .
, , .
func testShape(shape: Shape) {
print(shape.area())
print(shape.diameter())
}
. .
testShape(shape: Circle(radius: 5))
testShape(shape: Square(size: 5))
78.5
10.0
25.0
7.0710678118654755
, , , , - . – , .
Haskell
Haskell, , Swift.
data Shape = Circle Double | Square Double
area :: Shape -> Double
area (Circle r) = 3.14 * r * r
area (Square s) = s * s
diameter :: Shape -> Double
diameter (Circle r) = 2* r
diameter (Square s) = sqrt 2 * s
. , « » — . «» . .
— , , . Haskell — . , .
:
> area (Circle 5)
78.5
> diameter (Circle 5)
10.0
> area (Square 5)
25.0
diameter (Square 5)
7.0710678118654755
— — , .
, Swift Haskell .
, ,
, . , , — , — , , .
— , — . — , .
, : ? . .
, :
— .
, Swift.
Haskell…
data Shape = Circle Double | Square Double
… Swift .
enum Shape {
case Circle(radius: Double)
case Square(size: Double)
}
. «» , Swift «enum», . , .
Haskell…
area :: Shape -> Double
area (Circle r) = 3.14 * r * r
area (Square s) = s * s
… Swift .
extension Shape {
var area: Double {
switch self {
case .Circle(let r): return 3.14 * r * r
case .Square(let s): return s * s
}
}
}
, — .
Kotlin:
sealed class Shape {
data class Circle(val radius: Double): Shape()
data class Square(val size: Double): Shape()
}
fun area(sh: Shape): Double {
return when (sh) {
is Shape.Circle -> 3.14 * sh.radius * sh.radius
is Shape.Square -> sh.size * sh.size
}
}
, — .
, Kotlin Swift ? , , , . , -, .
. , , , , , .
, , , - — . . : — . , , .
. .
. . — - , — , . — .
— — . 20 , .
- «Visitor». , , . , .
- .
- — .
- .
- .
, « », . . , — , .
, .
, : , , , . , .

Haskell. , , , «» ?
, «» — .
— «Composite». . , .
, Kotlin — .
val a = "Hello "
val b = "world"
val c = a + b
, : «, ? ». , —
- .
— HTTP-. Kotlin :
val a = HttpReq("f","v1")
val b = HttpReq("f2","v2")
val c = a + b
Haskell , . HTTP- — . HTTP-.
.
. - . — , — , . «optional chaining», , Swift.
if let johnsStreet = john.residence?.address?.street
{ /* SUCCESS */ } else { /* FAILURE */ }
, . «john» — .
: , , . — . , else — . .
Swift . , , , : .
Haskell, .
case residence john >>= address >>= street of
Just johnsStreet -> -- SUCCESS
Nothing -> -- FAILURE
,
«>>=» — . .
Swift «optional chaining» . Kotlin . Haskell , «>>=».
:
. . , . , — , .
, — .
«» . — , . «», . « » .
— ?
. , — .
,
— . Haskell
«Build Systems a la Carte» . Distinguished Paper Award International Conference on Functional Programming (ICFP) - 2018 . Build-, .
Build- Build- — . .
data Store i k v
:
- i — ;
- k — , , ;
- v — , , , .
— . — , . .
. , , . , - -, , .
—
«Task» — .
newtype Task c k v = Task { run :: forall f. c f => (k -> f v) -> f v }
Haskell, . , — «f», . , .
? «k -> fv» — - . . . Build-.
— :
type Tasks c k v = k -> Maybe (Task c k v)
, , . «Maybe» — - «optional». , - - , .
Build-:
type Build c i k v = Tasks c k v -> k -> Store i k v
-> Store i k v
. k, . — . , .
.
- Make,
- Shake — Make Haskell,
- Bazel,
- Excel.
. — Excel — . Excel — . , - . Make Excel - , .
—
.
— Haskell . , ., . - — . , , . ,
.
, Haskell:
h :: [a] -> Int
h = length . filter p . map g . map f
— . - , :
map f
— f
;map g
— g
;filter p
— : , , ;length
— — .
:
— , , … ! !, .
Fusion
«fusion», .
«fusion»? -: :
c := 0
foreach (x : xs)
if p(g(f(x)))
then c := c + 1
,
(!),
(!). , , 2-3 .
, , , . — .
, .
GPU? !
Haskell, :
dotp :: Acc (Vector Float) -> Acc (Vector Float) -> Acc (Scalar Float)
dotp xs ys = fold (+) 0 (zipWith (*) xs ys)
, Haskell: 2 , , . , Haskell GPU. GPU, : CUDA, Open CL — , . Accelerate Haskell — .
CUDA 100 , , . ! , . , .
— . ? a, b, c D.
f :: A -> B -> C -> D
f a b c = ...
, — . , :
f :: A -> B -> C -> D
f a :: B -> C -> D
f a b :: C -> D
f a b c :: D
, . , , - , . — , , .
, , Scala -.
f :: A -> (B , C) -> D
f a p = …
f :: A -> B -> C -> D
f a :: (B, C) -> D
f a p :: D
: « , . , . , — ». .
, .
. Haskell 15 QuickCheck, .
, , :
reverse :: String -> String
reverse = ...
, . , .
> quickCheck (\s -> reverse (reverse s) == s)
+++ OK, passed 100 tests.
, . , 100, , , .
, , . . Haskell 15 . . , Swift Kotlin .
, ?
abs :: Int -> Int
abs x = if x < 0 then 0 - x else x
head :: [a] -> a -- !
head (x:_) = x
example :: Int -> Int
example x = if abs x < 0 then head [] else x
,
.
head :: [a] -> a -- !
head (x:_) = x
,
head
, — .
«head», ? , LiquidHaskell . LiquidHaskell — Haskell-.
{-@ abs :: Int -> { n : Int | 0 <= n } @-}
abs :: Int -> Int
abs x = if x < 0 then 0 - x else x
{-@ head :: { xs : [a] | 1 <= len xs } -> a @-}
head :: [a] -> a -- !
head (x:_) = x
{-@ head :: { xs : [a] | 1 <= len xs } -> a @-}
head :: [a] -> a -- !
head (x:_) = x
, abs , n.
{-@ abs :: Int -> { n : Int | 0 <= n } @-}
abs :: Int -> Int
abs x = if x < 0 then 0 - x else x
, .
{-@ head :: { xs : [a] | 1 <= len xs } -> a @-}
head :: [a] -> a -- !
head (x:_) = x
, , . x x.
{-@ example :: x : Int -> { y : Int | x == y } @-}
example :: Int -> Int
example x = if abs x < 0 then head [] else x
, . , . , - . - - , , Eiffel, - .
?
-:
type MyAPI = Get '[PlainText] String
:<|> "conf" :> Get '[JSON] String
:<|> "year" :> Get '[JSON] Int
:<|> "like" :> Get '[JSON] Bool
myAPI :: Server MyAPI
= root :<|> year :<|> conf :<|> like
Haskell Servant, API . , url , , , JSON. , : String», Int», Bool.
.
root :: Handler String
root = pure "Welcome to my REST API"
conf :: Handler String
conf = pure "AppsConf"
year :: Handler Int
year = pure 2019 conf
like :: Handler Bool
like = pure True
— , .
, . , , . — .
— . , . .
—
« Haskell». 2018 . , . Haskell. 600 , .
«Haskell in Depth» . , , . «slbragilevsky» 42%.
Saint AppsConf , Introductory- , . , , . , iOS, Android, - — . , , .
telegram-, .