functional programming

Yuriy Taras

Advertisement


200 000 000 Active users / month
2 000 000 open TCP connections / physical server

Server side: Erlang on FreeBSD 


500 000 000 tweets / day
200 000 000 users

Ruby on Rails, Scala

Spark


Implemented on Scala, use functional idioms for API
 spark/bagel/src/main$ wc -l **/*.scala
...  592 total

AXD301

99.5% = 1.83 days/year
99.95% = 4.38 hours/year
99.999% = 5.26 minutes/year
99.9999999% = 0.63113 seconds/20 years

Observed in AXD301 telecom switch,
 software layer implemented with Erlang
Due to Haskell’s strongly typed design, once we compiled our code, it just worked.
Netrium, Energy Contracts Management System

 
Haskell enabled us to get into market in less than half the time!
Silk, Web structured content management application

 
Haskell does exactly what we need it to do every time.
JUMP, Online user management SaaS
OCaml’s type system <...> helps improve the quality of our code, catching bugs at the earliest possible stage. Billions of dollars of transactions flow through our systems every day, so getting it right matters.
JaneStreet, trading firm


Developed by Microsoft Research
Integrated into Visual Studio 2010
Heavy influence from OCaml and Haskell


LINQ, type inference, higher order functions and lambdas

higher order functions, lambdas, type inference

FP becomes mainstream


iMPERATIVE PARADIGM


.top
	; add num1 to num2
	mov	di,num1+digits-1
	mov	si,num2+digits-1
	mov	cx,digits	; 
	call	AddNumbers	; num2 += num1
	mov	bp,num2		;
	call	PrintLine	;
	dec	dword [term]	; decrement loop counter
	jz	.done		;

	; add num2 to num1
	mov	di,num2+digits-1
	mov	si,num1+digits-1
	mov	cx,digits	;
	call	AddNumbers	; num1 += num2

FUNCTIONAL PARADIGM

tan x = sin x / cos x

less is more



pure function

Function can't rely on any state but it's parameters
 f(1) === f(1)
Function can't have any side effects
 int f(int x) {  return x * 2;  }

"forbidden" functions

 rand() print() writeFile() readLn()

referential TRANSPARENCY

 fac(3) === 6

You can replace function call with a value
  • at compile time
  • calculated in other thread
  • calculated on other machine
  • cached from previous call

other forbidden things

 def a(b: Int): Int = {   b = b + 5   b }

loops?

int factorial(int i) {
  int res = 1;
  for(j = i; j >= 2; j++) {    res *= j;  }  return res;
} 

recursion

 def fac(i: Int): Int = if (i <= 1) 1 else fac(i - 1) * i 

fail

scala> fac(50000)
java.lang.StackOverflowError
	at .fac(:7) 


NOT TURING COMPLETE :(

tail call optimization

 def tailFac(i: Int, accumulator: Int) =    if (i <= 1)    accumulator   else tailFac(i -1, accumulator * i)
def factorial(i: Int) = tailFac(i, 1)

functions as first-class citizens


> let x = 0.0
> let y = sin
> y x
0.0 

higher order functions

> def twice(fun: Double => Double, x: Double) = fun(fun(x))
> twice(Math.sin, 0)
res4: Double = 0.0
> twice(Math.cos, 0)
res6: Double = 0.5403023058681398

Lambda

> twice(_ * 2, 3)
res7: Double = 12.0
> def multiplier(x: Int): Int => Int = { x * _ }
> val mul2 = multiplier(2)
> mul2(4)
res9: Int = 8
> multiplier(4)(5)
res11: Int = 20 


Cons and nil



collection functional api

> List(1, 2, 3) map { _ * 2 }
res13: List[Int] = List(2, 4, 6) 
> List(1, 2, 3) filter { _ % 2 != 0 }
res15: List[Int] = List(1, 3) 
> List(1, 2, 3) flatMap { x => List(x, x+1) }
res16: List[Int] = List(1, 2, 2, 3, 3, 4) 
> List(1, 2, 3) reduceLeft { _ + _ }
res18: Int = 6
> List(1, 2, 3) reduceLeft { _ * _ }
res19: Int = 6 
> List(1, 2, 3).foldLeft("") {(x: String, y: Int) => x + y.toString }
res29: java.lang.String = 123 

one api to rule them all



  • List
  • Array
  • Set
  • Stack
  • String
  • Map
  • Lazy stream
  • Future (Akka)
  • Distributed dataset (Spark)
  • Option

billion dollar MISTAKE


I call it my billion-dollar mistake. It was the invention of the null reference in 1965.



String getUserName(Id id) {  User user = UserService.getUser(id);  if (user == null) return null;  Profile profile = user.getProfile();  if (profile != null) return null;  return profile.name;} 
def UserService.getUser(id: Id): User // Is there user or not? 
Can you spot a bug?
def UserService.getUser(id: Id): Option[User]
UserService.getUser(id).profile // compile error 
def getUserName(id: Id) = UserService.getUser(id) flatMap {                             _.profile } map { _.name } 


(sorry (but (I have) (no (time to show 'Lisp 'features)))) 
data Missing = Algebraic | Data Types

Notable languages

Scala

Java interop, C-like syntax, hybrid OO/FP, lot of experimental features

Haskell

Lazy, pure, type-safe, static typing, lightweight syntax


OCaml

mostly pure, type-safe, unfamiliar syntax, static typing, optional mutability and OO

F#

.Net interop, mostly pure, type-safe,
other things like OCaml

Scheme

mostly pure, dynamic, no syntax, consistent design


Clojure

mostly pure, dynamic with optional static typing, Java interop, compiles to bytecode, STM, optional OO


ERLANG

pure functions, lightweight threads aka actors, dynamic, optional type checking, MPS - concurrent and distributed, hot code reload

functional programming

By Yura Taras

functional programming

  • 624