Mach mir nichts vor mit deiner funktionalen Programmierung

AnhĂ€nger der funktionalen Programmierung locken Neulinge gerne mit dem Versprechen perfekter Code-Ausdruckskraft, 100% iger Korrektheit, einfacher UnterstĂŒtzung und einfacher Umgestaltung und sagen manchmal sogar die höchste Leistung voraus. Erfahrene Entwickler wissen jedoch, dass dies nicht der Fall ist. Programmieren ist harte Arbeit und „magische Pillen“ gibt es nicht.

Andererseits sind Elemente eines funktionalen Programmierstils bereits in industrielle Programmiersprachen wie Swift und Kotlin eingedrungen. Die Entwickler dieser Sprachen sind mit der funktionalen Programmierung bestens vertraut, sodass sie sie „im Kleinen“ verwenden konnten und viele, wenn auch nicht alle der erforderlichen Komponenten bereitstellten. Je weiter - desto mehr Teile der FI werden in industrielle Atomwaffen eingefĂŒhrt und desto besser und umfassender wird die UnterstĂŒtzung umgesetzt.

In der Lage zu sein, in einem funktionalen Stil zu programmieren, ist nĂŒtzlich, um Ihre Arbeit zu vereinfachen, und jetzt werden wir sehen, wie man es benutzt!


Vitaly Bragilevsky ist Lehrer fĂŒr FP, Theorie der Algorithmen und Berechnung, Autor des Buches "Haskell in Depth" und Mitglied der Haskell 2020-Komitees und des Überwachungskomitees des GHC-Compilers.

Kurze Geschichte


Funktionale Programmiergeschichten sind nicht immer wahr. Oft wird so ĂŒber AF gesprochen.

„Es war einmal in einer fernen Galaxie, die Programmierung war einfach, unkompliziert und gut. Algorithmen und Datenstrukturen sind programmiert und alles ist in Ordnung - keine Probleme!

Dann kamen die beĂ€ngstigenden Sith- Leute, die entschieden, dass alle Programme aus Klassen bestehen: '' Objektorientierte Programmierung fĂŒr alle! Alles muss nur mit solchen Methoden geschrieben werden. ''

Als sie an StĂ€rke gewannen, wurde es unmöglich, Software zu entwickeln - es traten viele Probleme auf. Um die unglĂŒcklichen leidenden Entwickler zu retten, gibt es funktionale Programmierung. "

Die Hauptsache bei der Errettung ist es, ein schönes und bedeutungsloses Bild zu zeichnen.



Wenn Sie alles auf dem Bild anwenden, werden GlĂŒck, Frieden und Ruhe kommen und die Probleme der Softwareentwicklung werden gelöst.

Die Geschichte ist wunderschön, aber in Wirklichkeit ist alles anders. So vertrete ich funktionale und industrielle Programmierung.



Funktionale Programmierung ist das Labor von Faraday - der Geburtsort von Ideen, die dann in der industriellen Programmierung angewendet werden.

In einem GesprĂ€ch ĂŒber industrielle Programmiersprachen sollten die Konzepte, ob sie funktionsfĂ€hig sind oder nicht, ob sie FP verwenden oder nicht, nicht angesprochen werden!

Die Hauptaufgabe der FP ist es, den Mainstream-Sprachen gute Elemente zu vermitteln.

Alle auf funktionierende Schienen ĂŒbertragen zu wollen, ist dasselbe wie Wissenschaftler zu Experimenten wie Faraday zu zwingen - es macht keinen Sinn. Derzeit fĂŒhrt niemand Experimente mit so veralteten Methoden zur ElektrizitĂ€t durch.

Schauen wir uns Beispiele an.

John McCarthy Funktion


John McCarthy ist einer der Schöpfer von Lisp.



Fortran war vor 65 Jahren die Hauptprogrammiersprache. Es hat eine bedingte Aussage:

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

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


All Articles