Upload
eivind-waaler
View
428
Download
0
Embed Size (px)
Citation preview
FunksjonellProgrammering på JVM
Eivind Barstad Waaler
www.wordle.net
Java Bytecode
� �x = 5 + 6 ; // Java� �
� �( de f x (+ 5 6) ) ; C l o j u r e� �
� �0 i load_1 // Java bytecode1 i load_22 iadd3 i s t o r e_3� �
� �add eax , edx ; Assemble rmov ecx , eax� �
Hva?
• Første-ordens funksjoner• Rene funksjoner• Rekursjon• Lat evaluering• Avanserte typesystemer/pattern matching
Trenger vi funksjoner i Java?
� �L i s t <St r i ng > navn eL i s t e = . . .
L i s t <St r i ng > navnPaaE = new Ar r a yL i s t <St r i ng >() ;f o r ( S t r i n g navn : n a vn eL i s t e ) {
i f ( navn . s t a r t sW i t h ( "E" ) ) {navnPaaE . add ( navn ) ;
}}� �
� �v a l na vn eL i s t e : L i s t [ S t r i n g ] = . . .
v a l navnPaaE = navn eL i s t e . f i l t e r (_ s t a r t sW i t h "E" )� �
Første-ordens funksjoner
Flickr: akash_k
Scala
� �// Funks jon som v a r i a b e lv a l p a r t a l l = ( x : I n t ) => x % 2 == 0p a r t a l l ( 4 ) // t r u e
// Funks jon som argumentv a l parU20 = (1 u n t i l 20) . f i l t e r ( p a r t a l l )
// Anonym funk s j o nv a l parU20 = (1 u n t i l 20) . f i l t e r (_ % 2 == 0)� �
JRuby
� �# Funks jon som v a r i a b e lp a r t a l l = lambda { | x | x % 2 == 0 }p a r t a l l . c a l l ( 4 ) # t r u e
# Funks jon som argumentparU20 = ( 1 . . . 2 0 ) . f i n d_ a l l { p a r t a l l }
# Anonym funk s j o nparU20 = ( 1 . . . 2 0 ) . f i n d_ a l l { | x | x % 2 == 0 }� �
Groovy
� �// Funks jon som v a r i a b e lp a r t a l l = { i t % 2 == 0 }p a r t a l l ( 4 ) // t r u e
// Funks jon som argumentparU20 = (1 . . <20) . f i n d A l l ( p a r t a l l )
// Anonym funk s j o nparU20 = (1 . . <20) . f i n d A l l ({ i t % 2 == 0})� �
Clojure
� �; D e f i n e r f u n k s j o n som v e r d i( de fn p a r t a l l [ x ] (= 0 (mod x 2) ) )( p a r t a l l 4) ; t r u e
; Funks jon som argument( de f parU20
( f i l t e r p a r t a l l( range 20) ) )
; Anonym funk s j o n( de f parU20
( f i l t e r ( fn [ x ] (= 0 (mod x 2) ) )( range 20) ) )� �
Java 7
� �// Funks jon som v a r i a b e l#i n t ( i n t ) p a r t a l l = #( i n t x ) {x % 2 == 0}p a r t a l l ! ( 4 ) // t r u e
// Funks jon som argumentL i s t <I n t e g e r > t i l 2 0 = // Lag a r r a y med t a l l e n e 1 t i l 20L i s t <I n t e g e r > parU20 = t i l 2 0 . f i l t e r ( p a r t a l l )
// Anonym funk s j o nL i s t <I n t e g e r > parU20 = t i l 2 0 . f i l t e r (
#( i n t x ) {x % 2 == 0})� �
Klasser i Java� �i n t e r f a c e Funct ion<A, R> {
R exec (A arg ) ;}
Funct ion<I n t e g e r , Boolean> p a r t a l l =new Funct ion<I n t e g e r , Boolean >() {
p ub l i c Boolean exec ( I n t e g e r a rg ) {r e t u r n arg % 2 == 0 ;
}} ;
i n t e r f a c e L i s t <T> {L i s t f i l t e r ( Funct ion<T, Boolean> fn ) ;
}
L i s t nummer = . . .
nummer . f i l t e r (new P a r t a l l ( ) )� �
Rene funksjoner
Rene funksjoner er tabeller!� �def PI = 3.14
def dobbe l ( x : I n t ) = x ∗ 2
def leggSammen ( x : I n t , y : I n t ) = x + y� �Funksjon Argumenter ReturverdiPI - 3.14
dobbel 2 4dobbel 21 42
leggSammen 2, 3 5leggSammen 20, 22 42
Fordeler med rene funksjoner
• Enhetstesting!• Samtidighet/parallell-prosessering• Caching/memoization
Clojure – memoization
� �( de fn s low−double [ n ]
( Thread/ s l e e p 100)(∗ n 2) )
( de f mem−double ( memoize s low−double ) )
( de f v a l u e s [ 1 2 1 2 1 2 ] )
( t ime ( dorun (map s low−double v a l u e s ) ) ); " E l apsed t ime : 602 .931 msecs "
( t ime ( dorun (map mem−double v a l u e s ) ) ); " E l apsed t ime : 200 .744 msecs "� �
Rekursjon
Escher - Drawing Hands (1948)
Rekursjon
• Stas i funksjonell programmering• Mange eksekveringer på stakken• Mye snakk om (mangel på) “tail-call optimization”
� �( de fn f i b [ n ]
( i f (<= n 1)1(+ ( f i b (− n 1) ) ( f i b (− n 2) ) )
))� �
Scala – tail-call optimization
� �def approx imate ( gue s s : Double ) : Double =
i f ( isGoodEnough ( gue s s ) ) gue s se l s e approx imate ( improve ( gue s s ) )� �
� �def approx imateLoop ( i n i t i a l G u e s s : Double ) : Double = {
va r gues s = i n i t i a l G u e s swh i l e ( ! isGoodEnough ( gue s s ) )
gue s s = improve ( gue s s )gue s s
}� �
Lat/utsatt evaluering
Flickr: ucumari
Scala – 2.7.x
� �// Re t u r n e r e r RandomAccessSeq . P r o j e c t i o n [ I n t ]v a l x5 = f o r ( i <− 0 to 10) y i e l d ( i ∗ 5)
// Fø r s t he r b l i r v e r d i e n k a l k u l e r tp r i n t l n ( "5 x 4 = " + x5 (4) )
// Samt id i ghe t s−pu z z l ev a l a c t o r s = f o r ( i <− 0 to 10) y i e l d a c t o r { . . . }� �
Scala – 2.8
� �// abba , r e gn i n g e r , t i l l i t , i n n idef i s P a l i n d r ome ( x : S t r i n g ) = x == x . r e v e r s edef f i n dPa l i n d r ome ( s : Seq [ S t r i n g ] ) =
s . f i n d ( i sPa l i n d r ome )
// M i d l e r t i d i g s ekven s en m i l l i o n e l emen t e rf i n dPa l i n d r ome ( words take 1000000)
// M i d l e r t i d i g s ekven s kun frem t i l f ø r s t e t r e f ff i n dPa l i n d r ome ( words . v iew take 1000000)� �
by-name param
� �// Typ i sk Java . . .i f ( debugLogEnabled ( ) ) {
l o g . debug ( "Tekst " + tungBeregn ing ( ) + " t e k s t " ) ;}� �
� �// Fo r e n k l e t s l f 4 sdef debug (msg : => S t r i n g ) =
i f ( debugLogEnabled ) {debugLog . w r i t e (msg )
}
// Typ i sk Sca l a . . . : )l o g . debug ( "Tekst " + tungBeregn ing + " t e k s t " )� �
Clojure – uendelige sekvenser
� �( de f p o s I n t s ( i t e r a t e i n c 0) )( take 10 p o s I n t s )
( de f r ands ( r e p e a t e d l y rand ) )( take 3 rands )� �
Avanserte typesystemer
Flickr: neverwasanarrow
Typesystemer
• Type inference• Implisitt konvertering• Pattern matching• Avanserte type-parametre/generics
� �v a l x = 5v a l x : I n t = 5
def add ( x : I n t , y : I n t ) = x + y
v a l l i s t = L i s t (1 , 2 , 3) // L i s t [ I n t ]v a l l i s t = L i s t (1 , 2 , 3 . 0 ) // L i s t [ AnyVal ]v a l l i s t = L i s t (1 , " to " , 3 . 0 ) // L i s t [ Any ]� �
Pattern matching
� �def desc ( x : Any ) = x match {
case 5 => " f i v e "case i : I n t i f i > 10 => " i n t : " + i . t o S t r i n gcase s : S t r i n g => " s t r : " + scase ( a , b ) => " t u p l e : " + a + bcase _ => "unknown"
}
desc (5 ) // " f i v e "desc (6 ) // "unknown"desc (11) // " i n t : 11"� �
Ytelse
Flickr: eole
Funksjonell programmering og ytelse
• Funksjonell vs. imperativ• Dynamisk vs. statisk typing• Autoboxing/primitiver• Data strukturer• Rene funksjoner - memoization• Samtidighet/parallell-prosessering
Løkker – for comprehension vs. while• Scala for comprehension – filter, map og flatMap• “Vanlig” løkke – while• 1000x1000 matrise + funksjoner:
• for med yield – 8090ms• for uten yield – 3507ms• while – 1865ms� �
v a l l i s t = f o r ( i <− 1 to 10) y i e l d ( i ∗ 2)
va r l i s t : L i s t [ I n t ] = N i lf o r ( i <− 1 to 10) l i s t += i ∗ 2
va r i = 1va r l i s t : L i s t [ I n t ] = N i lwh i l e ( i <= 10) {
l i s t += i ∗ 2i += 1
}� �
Dynamisk vs. statisk typing
• Legge til 1 i løkke 10 mill ganger• Dynamisk typing er tregt på JVM – invokedynamic• Obs! “Idiot”-implementasjoner� �
Java t ime : 8msGroovy t ime : 398msJRuby t ime : 1071msSca l a t ime : 18msC l o j u r e t ime : 300msC l o j u r e t ime : 186ms ( type h i n t s )� �� �( de f j 1)( p r i n t " C l o j u r e " )( t ime
( dot imes [ i 10000000](+ ( i n t i ) ( i n t j ) ) ) )� �
Andre foredrag på JavaZone:8. september:10:15 - Scala - fra newbie til ninja på en time11:45 - Howto: Implement Collaborative Filtering with Map/Reduce13:00 - Pattern matching in Scala14:15 - Kontoeksempelet i Java og Clojure14:15 - Akka: Simpler Scalability, Fault-Tolerance, Concurrency &Remoting through Actors15:45 - Erjang - A JVM-based Erlang VM17:00 - Cloud Computing with Scala and GridGain
9. september:17:00 - Practical use of Scala Actors
Flickr: ogil