函数式编程的拥护者喜欢以完美的代码表示能力,100%的正确性,易于支持和易于重构的方式吸引新手,甚至可以预测最高的性能。 但是,经验丰富的开发人员知道这不会发生。 编程是艰苦的工作,“魔药”不存在。
另一方面,函数式编程风格的元素已经渗透到工业编程语言中,例如Swift和Kotlin。 这些语言的开发人员对函数式编程非常熟悉,因此他们能够“少量”使用它,从而提供了许多(尽管不是全部)必要的组件。 距离越远,将FI的更多部分引入工业核武器中,支持的实施就越充分和充分。
能够以功能样式进行编程有助于简化您的工作,现在我们将了解如何使用它!
Vitaly Bragilevsky是FP的老师,算法和计算理论的作者,《深度的哈斯克尔》一书的作者,并且是Haskell 2020委员会和GHC编译器的监督委员会的成员。
历史简史
函数式编程的故事并不总是正确的。 人们经常这样谈论AF。
“从前在遥远的银河系中,编程是简单,直接和良好的。 对算法和数据结构进行了编程,一切都很好-没问题!
然后是西斯恐怖的人,他们决定所有程序都由类组成:''每个人的面向对象编程! 一切都只需要用这种方法来编写。
当他们获得实力时,就不可能开发软件了-出现了很多问题。 为挽救不幸的苦难开发人员,并提供了功能编程。”得救的主要目的是画出一幅美丽而毫无意义的图画。

当您应用图片中的所有内容时,幸福,和平与安宁就会到来,并且软件开发的问题将得到解决。
这个故事很美,但实际上一切都不同。 这就是我表示功能和工业编程的方式。

函数式编程是法拉第的实验室-法拉第的思想发源地,这些思想随后被应用到工业编程中。
在关于工业编程语言的对话中,不应提出它们是否起作用,是否使用FP的概念!
FP的主要任务是向主流语言传达良好的元素。
想要将所有人转移到功能轨道上,就像强迫科学家进行法拉第这样的实验一样,这没有任何意义。 目前没有人使用这种过时的方法进行电力实验。
让我们看一些例子。
约翰·麦卡锡(John McCarthy Function)
约翰·麦卡锡(John McCarthy)是Lisp的创建者之一。

65年前,Fortran是主要的编程语言。 它有一个条件语句:
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-, .