Les adeptes de la programmation fonctionnelle aiment attirer les nouveaux arrivants avec des promesses d'expressivitĂ© parfaite du code, de correction Ă 100%, de facilitĂ© de support et de refactorisation, et parfois mĂȘme de prĂ©dire les performances les plus Ă©levĂ©es. Cependant, les dĂ©veloppeurs expĂ©rimentĂ©s savent que cela ne se produit pas. La programmation est un travail difficile et les «pilules magiques» n'existent pas.
D'un autre cĂŽtĂ©, des Ă©lĂ©ments d'un style de programmation fonctionnel ont dĂ©jĂ pĂ©nĂ©trĂ© dans des langages de programmation industriels tels que Swift et Kotlin. Les dĂ©veloppeurs de ces langages connaissent bien la programmation fonctionnelle, ils ont donc pu l'utiliser «dans le petit», fournissant la plupart, mais pas la totalitĂ©, des composants nĂ©cessaires. Plus loin - plus il y a de parties de FI introduites dans les armes nuclĂ©aires industrielles, et mieux et plus complĂštement le soutien est mis en Ćuvre.
Pouvoir programmer dans un style fonctionnel est utile pour simplifier votre travail, et maintenant nous allons voir comment l'utiliser!
Vitaliy Bragilevsky est professeur de FP, de théorie des algorithmes et de calcul, auteur du livre "Haskell in Depth" et membre des comités Haskell 2020 et du comité de surveillance du compilateur GHC.
Bref historique
Les histoires de programmation fonctionnelle ne sont pas toujours vraies. Souvent, les gens parlent de la FA comme ça.
«Il était une fois dans une galaxie trÚs lointaine, la programmation était simple, directe et bonne. Les algorithmes et les structures de données sont programmés et tout va bien - pas de problÚmes!
Puis sont arrivĂ©es les personnes effrayantes Sith qui ont dĂ©cidĂ© que tous les programmes se composaient de classes: '' Programmation orientĂ©e objet pour tout le monde! Tout doit ĂȘtre Ă©crit uniquement par de telles mĂ©thodes. ''
Quand ils ont gagné en force, il est devenu impossible de développer des logiciels - beaucoup de problÚmes sont apparus. Pour sauver les malheureux développeurs qui souffrent, et il y a une programmation fonctionnelle. "L'essentiel dans le salut est de dessiner une image magnifique et dénuée de sens.

Lorsque vous appliquez tout dans l'image, le bonheur, la paix et la tranquillité viendront et les problÚmes de développement de logiciels seront résolus.
L'histoire est belle, mais en réalité tout est différent. C'est ainsi que je représente la programmation fonctionnelle et industrielle.

La programmation fonctionnelle est le laboratoire de Faraday - le berceau d'idées qui sont ensuite appliquées à la programmation industrielle.
Dans une conversation sur les langages de programmation industriels, les concepts de savoir s'ils sont fonctionnels ou non, qu'ils utilisent FP ou non, ne devraient pas ĂȘtre soulevĂ©s!
La principale mission du PC est de transmettre de bons éléments aux langues dominantes.
Vouloir transférer tout le monde sur des rails fonctionnels revient à forcer les scientifiques à mener des expériences comme Faraday - cela n'a aucun sens. Personne ne mÚne actuellement d'expériences sur l'électricité avec des méthodes aussi obsolÚtes.
Regardons des exemples.
Fonction John McCarthy
John McCarthy est l'un des créateurs de Lisp.

Fortran était le principal langage de programmation il y a 65 ans. Il a une déclaration conditionnelle:
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-, .