لا تخدعني مع البرمجة الوظيفية الخاصة بك

يحب أتباع البرمجة الوظيفية إغراء الوافدين الجدد بوعود بالتعبير التام عن الكود ، وصحة 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 . , , , . , , — , — , , .
CircleSquare
area**
diameter**
— , — . — , .

, : ? . .

, :

  • — ;
  • — , , , .

— .


, 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 ? , , , . , -, .


. , , , , , .
CircleSquarex
area**?
diameter**?
f???

, , , - — . . : — . , , .
CircleSquarex
area**+ ()
diameter**+ ()
f+ ()+ ()?

. .

. . — - , — , . — .


— — . 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» — .

  • ?. , , false. 
  • , .
  • .
  • — .

: , , . — . , else — . .

Swift . , , , : .

Haskell, .

case residence john >>= address >>= street of
    Just johnsStreet -> -- SUCCESS
    Nothing -> -- FAILURE

,  «>>=» — . .

Swift «optional chaining» . Kotlin . Haskell , «>>=». 

:

  • , , .
  • , 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 ff;
  • map gg;
  • 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-, .

Source: https://habr.com/ru/post/ar462505/


All Articles