Os adeptos da programação funcional gostam de atrair os novatos com promessas de perfeita expressividade do código, 100% de correção, facilidade de suporte e facilidade de refatoração e, às vezes, até prever o melhor desempenho. No entanto, desenvolvedores experientes sabem que isso não acontece. Programar é um trabalho árduo e não existem "pílulas mágicas".
Por outro lado, elementos de um estilo de programação funcional já penetraram em linguagens de programação industrial como Swift e Kotlin. Os desenvolvedores dessas linguagens estão familiarizados com a programação funcional, de modo que puderam usá-la "no pequeno", fornecendo muitos, embora não todos, os componentes necessários. Quanto mais longe - mais partes da FI são introduzidas nas armas nucleares industriais, e melhor e mais plenamente o apoio é implementado.
Ser capaz de programar em um estilo funcional é útil para simplificar o seu trabalho, e agora veremos como usá-lo!
Vitaly Bragilevsky é professor de FP, teoria dos algoritmos e computação, autor do livro "Haskell in Depth" e membro dos comitês Haskell 2020 e do comitê de supervisão do compilador GHC.
Breve histórico
Histórias de programação funcional nem sempre são verdadeiras. Muitas vezes, as pessoas falam sobre AF assim.
“Era uma vez em uma galáxia distante, a programação era simples, direta e boa. Algoritmos e estruturas de dados são programados e está tudo bem - sem problemas!
Depois vieram as pessoas assustadoras dos Sith que decidiram que todos os programas consistiam em aulas: '' Programação orientada a objetos para todos! Tudo precisa ser escrito apenas por esses métodos ''.
Quando eles ganharam força, tornou-se impossível desenvolver software - muitos problemas surgiram. Para salvar os infelizes desenvolvedores que sofrem, e há programação funcional ".O principal na salvação é desenhar uma imagem bonita e sem sentido.

Quando você aplica tudo na imagem, a felicidade, a paz e a tranquilidade surgirão e os problemas do desenvolvimento de software serão resolvidos.
A história é linda, mas na realidade tudo é diferente. É assim que eu represento a programação funcional e industrial.

A programação funcional é o laboratório de Faraday - o berço das idéias que são então aplicadas na programação industrial.
Em uma conversa sobre linguagens de programação industrial, os conceitos sobre se são funcionais ou não, se usam FP ou não, não devem ser levantados!
A principal missão do PF é transmitir bons elementos para os principais idiomas.
Querer transferir todos para trilhos funcionais é o mesmo que forçar os cientistas a realizar experimentos como Faraday - não faz sentido. Atualmente, ninguém está conduzindo experimentos com eletricidade com esses métodos obsoletos.
Vejamos exemplos.
Função John McCarthy
John McCarthy é um dos criadores do Lisp.

Fortran foi a principal linguagem de programação 65 anos atrás. Tem uma declaração condicional:
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-, .