Sztuczki w programowaniu

Transkrypt

Sztuczki w programowaniu
Sztuczki w programowaniu
Sztuczki w programowaniu
Cezary Bartoszuk
9 listopada 2010
Sztuczki w programowaniu
Wstęp
Ja
Cezary Bartoszuk
Info:
student MIMUW
zawodowo programista Pythona
Zainteresowania:
Języki programowania
Testowanie
Programowanie funkcyjne
...
Sztuczki w programowaniu
Wstęp
Plan
Co będzie?
Funkcje wyższych rzędów
Monady
Typy wyższych rzędów
Klasy abstrakcji na typach
Kontynuacje
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Funkcje wyższych rzędów
Funkcje wyższych rzędów
a raczej obywatele 1. kategorii
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Funkcje wyższych rzędów
Example
def id [ A ]( a : A ) = a
// id : [ A ]( a : A ) A
Example
def compose [A , B , C ]( inner : A = > B )( outer : B = > C ) =
( a : A ) = > outer ( inner ( a ))
// compose : [A ,B , C ]( inner : ( A ) = > B )( outer : ( B ) = > C )( A ) = > C
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Przykład: Programming Clojure
Example
( defn blank ? [ s ] ( every ? # ( Character / isWhitespace %) s ))
Example
public class StringUtils {
public static boolean isBlank ( String str ) {
int strLen ;
if ( str == null || ( strLen = str . length ()) == 0) {
return true ;
}
for ( int i = 0; i < strLen ; i ++) {
if ( Character . isWhitespace ( str . charAt ( i )) == false ) {
return false ;
}
}
return true ;
}
}
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Przykład
Theorem
isBlank(s : String ) ⇐⇒ ∀c∈s isWhitespace(c)
Example
( defn blank ? [ s ] ( every ? # ( Character / isWhitespace %) s ))
Example
def isBlank ( s : String ) = s forall Character . isWhitespace
// isBlank : ( s : String ) Boolean
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Praktyczny use-case
Nadanie własności metodzie/klasie. . .
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Praktyczny use-case
Nadanie własności metodzie/klasie. . .
monitor
transakcja
logowanie
aplikacja funkcji do wyniku
aplikacja szablonu do danych
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Dekoratory w Pythonie
Dekoratory!
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Szablony w aplikacji webowej
Example
class E x a m p l e C o n t r o l l e r ( B a s e R o u t i n g C o n t r o l l e r ):
@ expose ( ’ e x a m p l e _ t em p l a t e . html ’)
def example ( self ):
data = ...
return { ’ content ’: data }
def expose ( fn , template_path ):
def wrapped (* args , ** kwargs ):
result = fn (* args , ** kwargs )
renderer = Renderer . fromTemplate ( template_path )
return renderer . render ( result )
return wrapped
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Generyczne funkcje wyższych rzędów
Jakie są przykłady ogólnie stosowanych funkcji
wyższych rzędów?
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Map
f:
map f
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Filter
p:
filter p
Bool
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Filter
p
T
F
T
F
F
p:
filter p
Bool
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Fold
f
f
f:
x
f
f
f
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Fold
f:
f
x
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Fold
f:
f
f(
,
)=
x
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Fold
f:
f
f
f(
,
)=
x
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Fold
f:
f
f
f(
f
,
)=
x
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Fold
f
f
f(
,
f:
x
f
f
)=
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Fold
f
f
f(
,
f:
x
f
f
)=
f
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Implementacja
Example
def foldLeft [E , A ]
( acc : A ) ( list : List [ E ]) ( f : (A , E ) = > A ): A =
list match {
case Nil = > acc
case head :: tail = >
foldLeft ( f ( acc , head )) ( tail ) ( f )
}
// foldLeft : [E , A ]( f : (A , E ) = > A )( acc : A )( list : List [ E ]) A
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Implementacja
Example
def reverse [ A ] ( list : List [ A ]): List [ A ] =
foldLeft ( Nil : List [ A ]) ( list ) {
( reversed : List [ A ] , current : A ) = >
current :: reversed
}
// reverse : [ A ]( list : List [ A ]) List [ A ]
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Implementacja
Example
def filter [ A ] ( list : List [ A ]) ( p : A = > Boolean ) =
reverse {
foldLeft ( Nil : List [ A ]) ( list ) {
( filtered : List [ A ] , current : A ) = >
if ( p ( current )) {
current :: filtered
} else {
filtered
}
}
}
// filter : [ A ]( list : List [ A ])( p : ( A ) = > Boolean ) List [ A ]
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Implementacja
Example
def map [A , B ] ( list : List [ A ]) ( f : A = > B ): List [ B ] =
reverse {
foldLeft ( Nil : List [ B ]) ( list ) {
( computed : List [ B ] , current : A ) = >
f ( current ) :: computed
}
}
// map : [A , B ]( list : List [ A ])( f : ( A ) = > B ) List [ B ]
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Doskonała metoda na zmniejszenie ilości branchy?
Example
( defn blank ? [ s ] ( every ? # ( Character / isWhitespace %) s ))
Example
public class StringUtils {
public static boolean isBlank ( String str ) {
int strLen ;
if ( str == null || ( strLen = str . length ()) == 0) {
return true ;
}
for ( int i = 0; i < strLen ; i ++) {
if ( Character . isWhitespace ( str . charAt ( i )) == false ) {
return false ;
}
}
return true ;
}
}
Sztuczki w programowaniu
Przepływ danych
Funkcje wyższych rzędów
Wnioski
Funkje wyższych rzędów
Mogą zredukować ilość gałęzi wykonania kodu
Często prościej wyrazić to o co chodzi
Dekoratory są super!
Sztuczki w programowaniu
Przepływ danych
Monady
Monady
Monady
Sztuczki w programowaniu
Przepływ danych
Monady
Monady
(return x) = f = f x
m = return = m
(m = f ) = g = m = (λ x → f x = g )
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
j
i
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
j
i
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
j
i
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
j
i
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
j
i
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
j
i
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
j
i
Sztuczki w programowaniu
Przepływ danych
Monady
Obliczenie
g
f
h
???
j
???
i
Sztuczki w programowaniu
Przepływ danych
Monady
Problem?
Example
h: Data → Data
Otypowanie funkcji wyraża przekształcenie z Data w
Data.
Sztuczki w programowaniu
Przepływ danych
Monady
Problem?
Example
h: Data → Data
Otypowanie funkcji wyraża przekształcenie z Data w
Data.
Example
h: Data → Maybe[Data]
Teraz typy wyrażają to, że obliczenie może się nie
powieźć.
Sztuczki w programowaniu
Przepływ danych
Monady
Gdzie tu monady?
Monady są abstrakcją obliczenia.
Maybe abstrakcja niepowodzenia obliczenia
Collection abstrakcja wielu możliwych wyników
Error abstracja wyjątku
State abstracja modyfikacji stanu podczas obliczeń
Continuation abstrakcja zawieszonego obliczenia
Sztuczki w programowaniu
Przepływ danych
Monady
Wiki
a monad is a kind of abstract data type constructor
used to represent computations (instead of data in
the domain model). Monads allow the programmer to
chain actions together to build a pipeline, in which
each action is decorated with additional processing
rules provided by the monad.
Wikipedia
Sztuczki w programowaniu
Przepływ danych
Monady
Uporządkowana trójka?
M
konstruktor typów
return :
T → M [T ]
= : M [T ] → (T → M [U]) → M [U]
Sztuczki w programowaniu
Przepływ danych
Monady
Wnioski
Monady
Zwiększają wygodę programisty języka
funkcyjnego
Stanowią pewien model
Są trudne do zrozumienia
Sztuczki w programowaniu
Typy
Systemy typowania
Typy wyższych rzędów
Typy wyższych rzędów
Higher-Kinds
Sztuczki w programowaniu
Typy
Systemy typowania
?
Czym jest system typów?
Sztuczki w programowaniu
Typy
Systemy typowania
?
Czym jest system typów?
A type system is a tractable syntactic method for proving
the absence of certain program behaviors by classifying
phrases according to kinds of values they compute.
Benjamin Pierce
Sztuczki w programowaniu
Typy
Systemy typowania
?
Czym jest system typów?
A type system is a tractable syntactic method for proving
the absence of certain program behaviors by classifying
phrases according to kinds of values they compute.
Benjamin Pierce
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Piramida typów
???
Types
Values
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Piramida typów
Kinds
Types
Values
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Nieciekawy przykład
Example
type
type
type
type
Int :: *
String :: *
( Int = > String ):: *
List [ Int ]:: *
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Nieciekawy przykład
Example
type
type
type
type
type
type
Int :: *
String :: *
( Int = > String ):: *
List [ Int ]:: *
List :: ???
Function1 :: ???
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Ciekawy przykład
Example
type List
type Function1
def id ( i : Int ) = i
type Id [ A ] = A
def apply ( f : Int = > Int , i : Int ) = f ( a )
type Apply [ A [ _ ] , B ] = A [ B ]
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Ciekawy przykład
Example
// List :: * = > *
type List
// Function1 :: (* x *) = > *
type Function1
// id : ( Int ) = > Int
def id ( i : Int ) = i
// Id :: * = > *
type Id [ A ] = A
// apply : (( Int = > Int ) , Int ) = > Int
def apply ( f : Int = > Int , i : Int ) = f ( a )
// Apply :: ((* = > *) x *) = > *
type Apply [ A [ _ ] , B ] = A [ B ]
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Mnemonics
Co dałoby się poprawić w sposobie w jaki
generujemy dynamicznie bajtkod?
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Transformacje stosu
54
-12
R
iadd
42
R
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Prosta transformacja stosu
Example
def appendC alField
( calField : Int )
( start : F ): F = {
// Convention :
//
- Local variable 1 is the Calendar object
//
- Before this block , StringBuilder on top of the stack
//
- After this block , StringBuilder on top of the stack
start ~
aload (1) ~
bipush ( calField ) ~
method2 (( _ : Calendar ). get ( _ : Int )) ~
method2 (( _ : StringBuilder ). append ( _ : Int ))
}
trait F {
def ~( f : F = > F ): F
}
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Prosta transformacja stosu
Example
def appendC alField [ R <: Stack ]
( calField : Int )
( start : F [ R ** StringBuilder ]): F [ R ** StringBuilder ] = {
// Convention :
//
- Local variable 1 is the Calendar object
//
- Before this block , StringBuilder on top of the stack
//
- After this block , StringBuilder on top of the stack
start ~
aload (1) ~
bipush ( calField ) ~
method2 (( _ : Calendar ). get ( _ : Int )) ~
method2 (( _ : StringBuilder ). append ( _ : Int ))
}
trait F [+ ST <: Stack ] {
def ~[ ResST <: Stack ]( f : F [ Stack ] = > F [ ResST ]): F [ ResST ]
}
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Implementacja
Example
trait Stack
trait Nil extends Stack
case class Cons [+ R <: Stack , + T ] extends Stack
// Infix type alias
type ** [ X <: Stack , Y ] = Cons [X , Y ]
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Więcej?
HOList
HOMap
Obliczenia na poziomie typów
...
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Wnioski
Typy wyższych rzędów
Dają gwarancje poprawności tam, gdzie
możnaby się ich nie spodziewać
Bardziej generyczne otypowanie
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Klasy abstrakcji na typach
Klasy abstrakcji typów
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
sum ( List (1 , 2 , 3 , 4)) // = > 10
sum ( List (3.14 , 2.72)) // = > 5.86
sum ( List ( " a " , " bc " )) // ?!
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
trait Num [ A ] {
val zero : A
def add ( x : A , y : A ): A
}
def sum [ A ]( nums : List [ A ])( tc : Num [ A ]) =
nums . foldLeft ( tc . zero )( tc . add )
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
object IntNum extends Num [ Int ] {
val zero = 0
def add ( x : Int , y : Int ) = x + y
}
object DoubleNum extends Num [ Double ] {
val zero = 0 d
def add ( x : Double , y : Double ) = x + y
}
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
sum ( List (1 , 2 , 3 , 4))( IntNum )
sum ( List (3.14 , 2.72))( DoubleNum )
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
trait Num [ A ] {
val zero : A
def add ( x : A , y : A ): A
}
def sum [ A ]( nums : List [ A ])( tc : Num [ A ]) =
nums . foldLeft ( tc . zero )( tc . add )
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
trait Num [ A ] {
val zero : A
def add ( x : A , y : A ): A
}
def sum [ A ]( nums : List [ A ])( implicit tc : Num [ A ]) =
nums . foldLeft ( tc . zero )( tc . add )
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
object IntNum extends Num [ Int ] {
val zero = 0
def add ( x : Int , y : Int ) = x + y
}
object DoubleNum extends Num [ Double ] {
val zero = 0 d
def add ( x : Double , y : Double ) = x + y
}
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
implicit object IntNum extends Num [ Int ] {
val zero = 0
def add ( x : Int , y : Int ) = x + y
}
implicit object DoubleNum extends Num [ Double ] {
val zero = 0 d
def add ( x : Double , y : Double ) = x + y
}
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
sum ( List (1 , 2 , 3 , 4))( IntNum )
sum ( List (3.14 , 2.72))( DoubleNum )
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
sum ( List (1 , 2 , 3 , 4))
sum ( List (3.14 , 2.72))
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Przykład
Example
sum ( List (1 , 2 , 3 , 4))
sum ( List (3.14 , 2.72))
object MyIntNum extends Num [ Int ] {
val zero = 1
val add ( x : Int , y : Int ) = x * y
}
sum ( List (1 , 2 , 3 , 4))( MyIntNum )
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Inne przykłady
Ord, Eq
Coerce
Collects, FiniteMap
Addable
Sztuczki w programowaniu
Typy
Typy wyższych rzędów
Wnioski
Klasy abstrakcji typów
Fajniejszy sposób na pokazanie pewnych
zależności między typami
Pomaga w utrzymaniu Single Responsibility
Principle
Sztuczki w programowaniu
Przepływ sterowania
Kontynuacje
Kontynuacje
Właściwie ograniczone kontynuacje
Sztuczki w programowaniu
Przepływ sterowania
Go To considered harmful
Sztuczki w programowaniu
Przepływ sterowania
Głupie przykłady
goto
wyjątki
AIO
...
Sztuczki w programowaniu
Przepływ sterowania
Obsługa zdarzeń?
1
3
kodu aplikacji desktopowych Adobe stanowi
obsługa zdarzeń
1
2 zgłaszanych błędów pochodzi z tego kodu
Sztuczki w programowaniu
Przepływ sterowania
Obsługa zdarzeń?
1
3
kodu aplikacji desktopowych Adobe stanowi
obsługa zdarzeń
1
2 zgłaszanych błędów pochodzi z tego kodu
dlaczego mają tam tyle błędów?
Sztuczki w programowaniu
Przepływ sterowania
Inwersja kontroli
Example
var path : Path = null
val moveObserver = { ( event : MouseEvent ) = >
path . lineTo ( event . position )
draw ( path )
}
control . a d d M o u s e D o w n O b s e r v e r { event = >
path = new Path ( event . position )
control . a d d M o u s e M o v e O b s e r v e r ( moveObserver )
}
control . a d d M o u s e U p O b s e r v e r { event = >
control . r e m o v e M o u s e M o v e O b s e r v e r ( moveObserver )
path . close ()
draw ( path )
}
Sztuczki w programowaniu
Przepływ sterowania
Co jest złego w tym kodzie?
Efekty uboczne
¬ Enkapsulacja
Brak kompozycyjności
Niski poziom abstrakcji
Sztuczki w programowaniu
Przepływ sterowania
Wyższa abstrakcja?
Example
var path : Path = null
var moveObserver = null
observe ( control . mouseDown ) { event = >
path = new Path ( event . position )
moveObserver =
observe ( control . mouseMoves ) { event = >
path . lineTo ( event . position )
draw ( path )
}
}
observe ( control . mouseUp ) { event = >
moveObserver . dispose ()
path . close ()
draw ( path )
}
Sztuczki w programowaniu
Przepływ sterowania
Bez inwersji kontroli?
Example
Reactor . once { self = >
// step 1:
val path = new Path (( self next mouseDown ). position )
// step 2:
self loopUntil mouseUp {
val m = self next mouseMove
path . lineTo ( m . position )
draw ( path )
}
// step 3:
path . close ()
draw ( path )
}
Sztuczki w programowaniu
Przepływ sterowania
Signal Whitening
Example
val path : Signal [ Path ] =
Val ( new Path ) once { self = >
import self . _
val down = next ( mouseDown )
emit ( previous . moveTo ( down . position ))
loopUntil ( mouseUp ) {
val m = next ( mouseMove )
emit ( previous . lineTo ( m . position ))
}
emit ( previous . close )
}
Sztuczki w programowaniu
Przepływ sterowania
Wnioski
Kontynuacje
umożliwiają enkapsulację inwersji kontroli

Podobne dokumenty