kombinatoren - andrena · validation = user -> nameisnotempty.apply(user) &&...
TRANSCRIPT
![Page 1: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/1.jpg)
Kombinatoren
![Page 2: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/2.jpg)
Combinators
![Page 3: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/3.jpg)
Gregor Trefs
32 years old
Team Lead @LivePerson
Organizer of @majug
Founder of SWK Rhein-Neckar
twitter/github: gtrefs
![Page 4: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/4.jpg)
Who knows what
a function is?
a lambda expression is?
a combinator is?
![Page 5: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/5.jpg)
Recap: Functions
add :: Num a => a -> a -> aadd = \x -> \y -> x + y
![Page 6: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/6.jpg)
Recap: Functions
int addOne(int i){ return i+1; }
![Page 7: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/7.jpg)
Recap: Functions
Function<Integer, Integer> addOne;addOne = i -> i + 1;
Deduction Context
Lambda expression
![Page 8: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/8.jpg)
Recap: Functions
int compute(int i, Function<Int, Int> f)
Higher order
First order
![Page 9: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/9.jpg)
Recap: Functions
Function<Int, Int> makeAdder(int i){ return x -> x + i;}
Function<Int, Int> addOne = makeAdder(1)
Return value Factory
![Page 10: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/10.jpg)
Recap: Functions
Function<Int, Function<Int, Int>> f;
f = x -> (y -> x + y);
Function<Integer, Integer> addOne = f.apply(1);
Parameter of
first function
Returns function
Parameter of
returned function
Returns int
![Page 11: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/11.jpg)
Recap: Functions
addOne = f.apply(1); addTwo = f.apply(2);
Function<Int, Int> addThree = x -> addTwo.apply(addOne.apply(x));
addFive = addThree.compose(addTwo);
Typesafe composition
![Page 12: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/12.jpg)
Primitives and Combinators
Combine primitives into more complex structures
Function Functions Functions
![Page 13: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/13.jpg)
Primitives and Combinators
Primitives are uncombined functions
![Page 14: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/14.jpg)
Primitives and Combinators
Combinators compose primitives and/or structures into more complex structures
![Page 15: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/15.jpg)
Primitives and Combinators
Combinators are functions that build other functions
![Page 16: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/16.jpg)
Primitives and Combinators
User Validation
Function<User, Boolean>
![Page 17: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/17.jpg)
Primitives and Combinators
@Testpublic void yield_valid_for_user_with_email_and_non_empty_name(){ User gregor = new User("Gregor Trefs", 32, "[email protected]");
UserValidation validation = todo();
assertThat(validation.apply(gregor), is(true));}
interface UserValidation extends Function<User, Boolean> {}
![Page 18: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/18.jpg)
Primitives and Combinators
@Testpublic void yield_valid_for_user_with_email_and_non_empty_name(){ User gregor = new User("Gregor Trefs", 32, "[email protected]"); UserValidation nameIsNotEmpty = user -> !user.name.trim().isEmpty(); UserValidation mailContainsAtSign = user -> user.email.contains("@"); UserValidation validation; validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user);
assertThat(validation.apply(gregor), is(true));}
interface UserValidation extends Function<User, Boolean> {}
![Page 19: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/19.jpg)
Primitives and Combinators
@Testpublic void yield_valid_for_user_with_email_and_non_empty_name(){ final User gregor = new User("Gregor Trefs", 32, "[email protected]"); final UserValidation validation = nameIsNotEmpty.and(mailContainsAtSign);
assertThat(validation.apply(gregor), is(true));}
public interface UserValidation extends Function<User, Boolean> { UserValidation nameIsNotEmpty = user -> !user.name.trim().isEmpty(); UserValidation mailContainsAtSign = user -> user.email.contains("@"); default UserValidation and(UserValidation other){ return user -> this.apply(user) && other.apply(user); }
default UserValidation or(UserValidation other){ return user -> this.apply(user) || other.apply(user); }}
![Page 20: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/20.jpg)
Return value reasoning
Embedded domain specific language: Primitives and combinators are from the
validation domain
![Page 21: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/21.jpg)
Return value reasoning
Separation of validation description and execution
![Page 22: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/22.jpg)
Return value reasoning
Validation has no shared mutable state
![Page 23: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/23.jpg)
Return value reasoning
Boolean is bad for representing validation results
![Page 24: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/24.jpg)
Return value reasoning
Hard to determine which rules invalidated the result
![Page 25: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/25.jpg)
Return value reasoning
Semantic is implicit and context specific
![Page 26: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/26.jpg)
Return value reasoning
Type for representing the validation result is needed
![Page 27: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/27.jpg)
Return value reasoning
@Testpublic void yield_invalid_for_user_without_email(){ User gregor = new User("Gregor Trefs", 32, ""); ValidationResult result = nameIsNotEmpty.and(eMailContainsAtSign).apply(gregor); assertThat(result.getReason().get(), is("E-Mail is not valid."));}
public interface UserValidation extends Function<User, ValidationResult> { UserValidation nameIsNotEmpty = todo(); UserValidation eMailContainsAtSign = todo(); default UserValidation and(UserValidation other){ return todo(); }}
![Page 28: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/28.jpg)
Return value reasoning
@Testpublic void yield_invalid_for_user_without_email(){ User gregor = new User("Gregor Trefs", 31, ""); ValidationResult result = nameIsNotEmpty.and(eMailContainsAtSign).apply(gregor); assertThat(result.getReason().get(), is("E-Mail is not valid."));}public interface UserValidation extends Function<User, ValidationResult> { UserValidation nameIsNotEmpty = user -> !user.name.trim().isEmpty()?valid():invalid("User name is empty"); UserValidation eMailContainsAtSign = user -> user.email.contains("@")?valid():invalid("E-Mail is not valid."); default UserValidation and(UserValidation other){ return user -> { ValidationResult result = this.apply(user); return result.isValid() ? other.apply(user) : result; }; }}
![Page 29: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/29.jpg)
Benefits and Disadvantages
Domain specific approach
![Page 30: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/30.jpg)
Benefits and Disadvantages
Implicit information is modelled explicit
![Page 31: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/31.jpg)
Benefits and Disadvantages
Separation of concerns in primitives and composability with combinators
![Page 32: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/32.jpg)
Benefits and Disadvantages
Extensibility by using the context
UserValidation ext; ext = nameIsNotEmpty.and(u -> …)
![Page 33: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/33.jpg)
Benefits and Disadvantages
Reusability: Once described, a function can be applied manyfold
![Page 34: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/34.jpg)
Benefits and Disadvantages
Does my team understand the concepts of functional programming?
![Page 35: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/35.jpg)
Benefits and Disadvantages
How to determine primitives and combinators?
![Page 36: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/36.jpg)
When to use it
Design your API with Combinators
Comparator
![Page 37: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/37.jpg)
When to use it
@Testpublic void sort_users_by_age_and_name(){ final User gregor = new User("Gregor Trefs", 32, "[email protected]"); final User petra = new User("Petra Kopfler", 30, "[email protected]"); final User robert = new User("Robert Schmidt", 32, "[email protected]");
Comparator<User> byAge = Comparator.comparing(user -> user.age); Comparator<User> byName = Comparator.comparing(user -> user.name); Comparator<User> byAgeThenName = byAge.thenComparing(byName);
assertThat(byAgeThenName.compare(gregor, petra), is(1)); assertThat(byAgeThenName.compare(gregor, robert), is(-11));}
![Page 38: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/38.jpg)
When to use it
JSON Encoding and Decoding
Function<JValue, DecodeResult<T>>Function<T, JValue>
![Page 39: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/39.jpg)
When to use it
@Testpublic void user_json_codec(){ var user = new User("Gregor Trefs",32,"[email protected]"); EncodeJson<User> encode = Encoders.encode( FieldEncoder.EString("name"), FieldEncoder.EInt("age"), FieldEncoder.EString("email")) .contramap(u -> Tuples.of(u.name, u.age, u.email)); DecodeJson<User> decode = Decoders.decode( FieldDecoder.TString("name"), FieldDecoder.TInt("age"), FieldDecoder.TString("email"), User::new);
var codec = JsonCodec.lift(decode, encode); var encodedThenDecoded = codec.fromJson(codec.toJson(user)).unsafeGet();
assertThat(encodedThenDecoded.email, is(user.email)); assertThat(encodedThenDecoded.age, is(user.age)); assertThat(encodedThenDecoded.name, is(user.name));}
![Page 40: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/40.jpg)
When to use it
To build functions
![Page 41: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/41.jpg)
When to use it
FizzBuzz: Number -> Word
Validation: User -> ValidationResult
Parsing: String -> AST
Projection: EventStream -> Aggregate
Encoding: Object -> JSON
Decoding: JSON -> T
![Page 42: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/42.jpg)
Local type inference: Impossible types
@Testpublic void use_combinators_from_different_namespaces(){ var gregor = new User("Gregor Trefs", 32, "[email protected]"); var validations = (NameValidations & AgeValidations) UserValidation::create;
var validator = validations.olderThan(20).and(validations.nameIsUpperCase()); var validationResult = validator.apply(gregor);
assertThat(validationResult.getReason().get(), containsString("upper case."));}public interface NameValidations extends UserValidation { default UserValidation nameIsUpperCase(){ … }}public interface AgeValidations extends UserValidation { default UserValidation olderThan(int age){ … }}public interface UserValidation extends Function<User, ValidationResult> { static ValidationResult create(User user){ throw new UnsupportedOperationException(); }}
![Page 44: Kombinatoren - andrena · validation = user -> nameIsNotEmpty.apply(user) && mailContainsAtSign.apply(user); ... functional programming? Benefits and Disadvantages How to determine](https://reader034.vdocuments.mx/reader034/viewer/2022051912/60032362a1096662880f8c0e/html5/thumbnails/44.jpg)
● My blog post about the topic
http://bitly.com/2lryGxJ
● Functional Programming in
Scala (The red one)
Java (The blue one)
● Background picture by
John Salzarulo
Literatureand links