Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
Effect monads like IO are the way functional programmers interact with the real world. Yet, monadic effects in programming languages like Scala often perform poorly compared to their Haskell counterparts—as much as 10x slower in some benchmarks. In this presentation, John A. De Goes, author of the Scalaz 8 effect system, dredges up an old paper to cast new light on the question of how to model effects, and comes to the surprising conclusion that in Scala, monads may not be the fastest way to model purely functional effects. Join John as he shows a new model of effects that offers performance improvements without sacrificing the wonderful purity that functional programmers rely on to reason about their software.
Introduces the functional programming ideas of Functor, Apply, Applicative And Monad. Shows how to implement each in Scala with Scalaz and how to validate the implementation using property based test using specs2 and scalacheck.
The Functional Programming Triad of Map, Filter and FoldPhilip Schwarz
This slide deck is my homage to SICP, the book which first introduced me to the Functional Programming triad of map, filter and fold.
It was during my Computer Science degree that a fellow student gave me a copy of the first edition, not long after the book came out.
I have not yet come across a better introduction to these three functions.
The upcoming slides are closely based on the second edition of the book, a free online copy of which can be found here:
https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book.html.
Download for original image quality.
Errata:
slide 20: the Clojure map function is in fact the Scheme one repeated - see code below for correction.
Scheme code: https://github.com/philipschwarz/the-fp-triad-of-map-filter-and-fold-scheme
Clojure code: https://github.com/philipschwarz/the-fp-triad-of-map-filter-and-fold-clojure
Left and Right Folds- Comparison of a mathematical definition and a programm...Philip Schwarz
We compare typical definitions of the left and right fold functions, with their mathematical definitions in Sergei Winitzki’s upcoming book: The Science of Functional Programming.
Errata:
Slide 13: "The way 𝑓𝑜𝑙𝑑𝑙 does it is by associating to the right" - should, of course ,end in "to the left".
Blazing Fast, Pure Effects without Monads — LambdaConf 2018John De Goes
Effect monads like IO are the way functional programmers interact with the real world. Yet, monadic effects in programming languages like Scala often perform poorly compared to their Haskell counterparts—as much as 10x slower in some benchmarks. In this presentation, John A. De Goes, author of the Scalaz 8 effect system, dredges up an old paper to cast new light on the question of how to model effects, and comes to the surprising conclusion that in Scala, monads may not be the fastest way to model purely functional effects. Join John as he shows a new model of effects that offers performance improvements without sacrificing the wonderful purity that functional programmers rely on to reason about their software.
Introduces the functional programming ideas of Functor, Apply, Applicative And Monad. Shows how to implement each in Scala with Scalaz and how to validate the implementation using property based test using specs2 and scalacheck.
The Functional Programming Triad of Map, Filter and FoldPhilip Schwarz
This slide deck is my homage to SICP, the book which first introduced me to the Functional Programming triad of map, filter and fold.
It was during my Computer Science degree that a fellow student gave me a copy of the first edition, not long after the book came out.
I have not yet come across a better introduction to these three functions.
The upcoming slides are closely based on the second edition of the book, a free online copy of which can be found here:
https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book.html.
Download for original image quality.
Errata:
slide 20: the Clojure map function is in fact the Scheme one repeated - see code below for correction.
Scheme code: https://github.com/philipschwarz/the-fp-triad-of-map-filter-and-fold-scheme
Clojure code: https://github.com/philipschwarz/the-fp-triad-of-map-filter-and-fold-clojure
Left and Right Folds- Comparison of a mathematical definition and a programm...Philip Schwarz
We compare typical definitions of the left and right fold functions, with their mathematical definitions in Sergei Winitzki’s upcoming book: The Science of Functional Programming.
Errata:
Slide 13: "The way 𝑓𝑜𝑙𝑑𝑙 does it is by associating to the right" - should, of course ,end in "to the left".
download for better quality - Learn about the sequence and traverse functions
through the work of Runar Bjarnason and Paul Chiusano, authors of Functional Programming in Scala https://www.manning.com/books/functional-programming-in-scala
Comparing JVM Web Frameworks - February 2014Matt Raible
My Comparing JVM Web Frameworks talk as presented at Denver's Open Source User Group (@dosug) and vJUG (@virtualjug). Covers the history of web frameworks as well as various methods for choosing one. Video on YouTube at https://www.youtube.com/watch?v=ygW8fJVlDxQ.
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Philip Schwarz
slides can look grainy and/or out of focus when seen on slideshare - download for flawless quality - Based on Scott Wlaschin’s great book 'Domain Modeling Made Functional' and on Martin Odersky's talk 'A Tour of Scala 3'.
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Haskell, Scala and Java.
Inspired by the example in Scott Wlaschin’s F# book: Domain Modeling Made Functional.
Download for better results.
Java 19 Code: https://github.com/philipschwarz/fruit-salad-and-fruit-snack-ADT-example-java
Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...Philip Schwarz
Follow in the footsteps of refactoring guru Martin Fowler as he improves the design of a program in a simple yet instructive refactoring example whose JavaScript code and associated refactoring is herein adapted to Scala.
Based on the second edition of ‘the’ Refactoring book.
Here is a github repository with the whole refactoring, from start to finish, following the steps seen in the slides https://github.com/philipschwarz/refactoring-a-first-example-scala
Nat, List and Option Monoids -from scratch -Combining and Folding -an examplePhilip Schwarz
Nat, List and Option Monoids, from scratch. Combining and Folding: an example.
Code: https://github.com/philipschwarz/nat-list-and-option-monoids-from-scratch-combining-and-folding-an-example
Modern applications are concurrent, parallel, asynchronous, and synchronous; they utilize many different subsystems, including network systems, actor systems, distributed systems, and more. Across all these modes of computation and different subsystems, the one constant is failure. Errors happen everywhere, and taming their monstrous complexity in a way that helps developers write correct code and troubleshoot failures is one of the hardest challenges of modern application development.
In this presentation, created just for the Dublin Scala Meetup, John A. De Goes and Kai from 7mind.io will take attendees on a tour of error management in Scala, comparing and contrasting Scala's own Future type, and the ZIO effect type. You'll see how functional effects provide features that go way beyond Future: including unified errors across all modes of computation, powerful error operators, lossless error propagation, compiler-assisted error handling, and a stunning new feature for debugging, sponsored by Irish consultancy 7mind.io, will be unveiled exclusively at this presentation.
Come learn about how modern functional effect systems like ZIO provide compelling new solutions to the problems of everyday error management.
Monad as functor with pair of natural transformationsPhilip Schwarz
Explains why a Monad is a functor with a pair of natural transformations (plus associativity and identity laws). It then explores this by looking at an example, with code in Scala.
Inspired and based on videos/publications by Bartosz Milewski, Rúnar Bjarnason and Rob Norris.
Download for better quality.
Some parts of our applications don't need to be asynchronous or interact with the outside world: it's enough that they are stateful, possibly with the ability to handle failure, context, and logging. Although you can use ZIO 2 or monad transformers for this task, both come with drawbacks. In this presentation, Jorge Vásquez will introduce you to ZPure, a data type from ZIO Prelude, which lets you scale back on the power of ZIO 2, but with the same high-performance, type-inference, and ergonomics you expect from ZIO 2 libraries.
Functional programming can be an excellent approach to designing decoupled, reusable systems with a rich domain model. In fact, the lessons from applying DDD in a functional language translate well to object-oriented programming.
download for better quality - Learn how to use an Applicative Functor to handle multiple independent effectful values through the work of Sergei Winitzki, Runar Bjarnason, Paul Chiusano, Debasish Ghosh and Adelbert Chang
Lambdas and Streams Master Class Part 2José Paumard
These are the slides of the talk we made with Stuart Marks at Devoxx Belgium 2018. This second part covers the Stream API, reduction and the Collector API.
What is the state of lambda expressions in Java 11? Lambda expressions are the major feature of Java 8, having an impact on most of the API, including the Streams and Collections API. We are now living the Java 11 days; new features have been added and new patterns have emerged. This highly technical Deep Dive session will visit all these patterns, the well-known ones and the new ones, in an interactive hybrid of lecture and laboratory. We present a technique and show how it helps solve a problem. We then present another problem, and give you some time to solve it yourself. Finally, we present a solution, and open for questions, comments, and discussion. Bring your laptop set up with JDK 11 and your favorite IDE, and be prepared to think!
download for better quality - Learn about the sequence and traverse functions
through the work of Runar Bjarnason and Paul Chiusano, authors of Functional Programming in Scala https://www.manning.com/books/functional-programming-in-scala, and others (Martin Odersky, Derek Wyatt, Adelbert Chang)
The lazy programmer's guide to writing thousands of testsScott Wlaschin
We are all familiar with example-based testing, as typified by TDD and BDD, where each test is hand-crafted.
But there's another approach to writing tests. In the "property-based testing" approach, a single test is run hundreds of times with randomly generated inputs. Property-based testing is a great way to find edge cases, and also helps you to understand and document the behavior of your code under all conditions.
This talk will introduce property-based testing, show you how it works, and demonstrate why you should consider adding this powerful technique to your toolbelt.
download for better quality - Learn about the sequence and traverse functions
through the work of Runar Bjarnason and Paul Chiusano, authors of Functional Programming in Scala https://www.manning.com/books/functional-programming-in-scala
Comparing JVM Web Frameworks - February 2014Matt Raible
My Comparing JVM Web Frameworks talk as presented at Denver's Open Source User Group (@dosug) and vJUG (@virtualjug). Covers the history of web frameworks as well as various methods for choosing one. Video on YouTube at https://www.youtube.com/watch?v=ygW8fJVlDxQ.
Scala 3 by Example - Algebraic Data Types for Domain Driven Design - Part 1Philip Schwarz
slides can look grainy and/or out of focus when seen on slideshare - download for flawless quality - Based on Scott Wlaschin’s great book 'Domain Modeling Made Functional' and on Martin Odersky's talk 'A Tour of Scala 3'.
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Haskell, Scala and Java.
Inspired by the example in Scott Wlaschin’s F# book: Domain Modeling Made Functional.
Download for better results.
Java 19 Code: https://github.com/philipschwarz/fruit-salad-and-fruit-snack-ADT-example-java
Refactoring: A First Example - Martin Fowler’s First Example of Refactoring, ...Philip Schwarz
Follow in the footsteps of refactoring guru Martin Fowler as he improves the design of a program in a simple yet instructive refactoring example whose JavaScript code and associated refactoring is herein adapted to Scala.
Based on the second edition of ‘the’ Refactoring book.
Here is a github repository with the whole refactoring, from start to finish, following the steps seen in the slides https://github.com/philipschwarz/refactoring-a-first-example-scala
Nat, List and Option Monoids -from scratch -Combining and Folding -an examplePhilip Schwarz
Nat, List and Option Monoids, from scratch. Combining and Folding: an example.
Code: https://github.com/philipschwarz/nat-list-and-option-monoids-from-scratch-combining-and-folding-an-example
Modern applications are concurrent, parallel, asynchronous, and synchronous; they utilize many different subsystems, including network systems, actor systems, distributed systems, and more. Across all these modes of computation and different subsystems, the one constant is failure. Errors happen everywhere, and taming their monstrous complexity in a way that helps developers write correct code and troubleshoot failures is one of the hardest challenges of modern application development.
In this presentation, created just for the Dublin Scala Meetup, John A. De Goes and Kai from 7mind.io will take attendees on a tour of error management in Scala, comparing and contrasting Scala's own Future type, and the ZIO effect type. You'll see how functional effects provide features that go way beyond Future: including unified errors across all modes of computation, powerful error operators, lossless error propagation, compiler-assisted error handling, and a stunning new feature for debugging, sponsored by Irish consultancy 7mind.io, will be unveiled exclusively at this presentation.
Come learn about how modern functional effect systems like ZIO provide compelling new solutions to the problems of everyday error management.
Monad as functor with pair of natural transformationsPhilip Schwarz
Explains why a Monad is a functor with a pair of natural transformations (plus associativity and identity laws). It then explores this by looking at an example, with code in Scala.
Inspired and based on videos/publications by Bartosz Milewski, Rúnar Bjarnason and Rob Norris.
Download for better quality.
Some parts of our applications don't need to be asynchronous or interact with the outside world: it's enough that they are stateful, possibly with the ability to handle failure, context, and logging. Although you can use ZIO 2 or monad transformers for this task, both come with drawbacks. In this presentation, Jorge Vásquez will introduce you to ZPure, a data type from ZIO Prelude, which lets you scale back on the power of ZIO 2, but with the same high-performance, type-inference, and ergonomics you expect from ZIO 2 libraries.
Functional programming can be an excellent approach to designing decoupled, reusable systems with a rich domain model. In fact, the lessons from applying DDD in a functional language translate well to object-oriented programming.
download for better quality - Learn how to use an Applicative Functor to handle multiple independent effectful values through the work of Sergei Winitzki, Runar Bjarnason, Paul Chiusano, Debasish Ghosh and Adelbert Chang
Lambdas and Streams Master Class Part 2José Paumard
These are the slides of the talk we made with Stuart Marks at Devoxx Belgium 2018. This second part covers the Stream API, reduction and the Collector API.
What is the state of lambda expressions in Java 11? Lambda expressions are the major feature of Java 8, having an impact on most of the API, including the Streams and Collections API. We are now living the Java 11 days; new features have been added and new patterns have emerged. This highly technical Deep Dive session will visit all these patterns, the well-known ones and the new ones, in an interactive hybrid of lecture and laboratory. We present a technique and show how it helps solve a problem. We then present another problem, and give you some time to solve it yourself. Finally, we present a solution, and open for questions, comments, and discussion. Bring your laptop set up with JDK 11 and your favorite IDE, and be prepared to think!
download for better quality - Learn about the sequence and traverse functions
through the work of Runar Bjarnason and Paul Chiusano, authors of Functional Programming in Scala https://www.manning.com/books/functional-programming-in-scala, and others (Martin Odersky, Derek Wyatt, Adelbert Chang)
The lazy programmer's guide to writing thousands of testsScott Wlaschin
We are all familiar with example-based testing, as typified by TDD and BDD, where each test is hand-crafted.
But there's another approach to writing tests. In the "property-based testing" approach, a single test is run hundreds of times with randomly generated inputs. Property-based testing is a great way to find edge cases, and also helps you to understand and document the behavior of your code under all conditions.
This talk will introduce property-based testing, show you how it works, and demonstrate why you should consider adding this powerful technique to your toolbelt.
Lightening Talk I gave at Inaka in November 2015, after having developed Swift for a while.
It contains some lessons, mostly learned from the functional paradigm, that can be useful for any developer.
I am Samuel H. I am a Python Homework Expert at pythonhomeworkhelp.com. I hold a Master's in Python Programming from, the University of Alberta, Canada. I have been helping students with their homework for the past 7 years. I solve homework related to Python.
Visit pythonhomeworkhelp.com or email support@pythonhomeworkhelp.com.
You can also call on +1 678 648 4277 for any assistance with Python Homework.
One of the advantages of learning a new language is being exposed to new idioms and new approaches to solving old problems. In this talk, we will introduce the Ruby language with particular focus on the idioms and concepts that are different from what is found in Java.
We will introduce concepts such as closures, continuations and meta programming. We will also examine powerful techniques that are practically impossible in Java due to its compile time binding of types.
No experience with Ruby is assumed although an understanding of Java would be helpful.
This talk was given at the Toronto Java Users Group in April 2008
The slides of my JavaOne 2016 talk. This talk is a tutorial on how to write lambda expressions, how to compose them using default methods in functional interfaces, and how to create factory methods in those interfaces. Many examples and patterns are provided.
The slides of my JavaOne 2017 talk. It describes how you can create API using functional interfaces, default and static methods starting with Java 8. You can watch the video here: https://www.youtube.com/watch?v=64UO1YjVcZ0
This is the third presentation in pySIG 2015 @ BMS College of Engineering, Bangalore. The code and assignments can be found at https://github.com/pranavsb
Here I link up up some very useful material by Robert Norris (@tpolecat) and Martin Odersky (@odersky) to introduce Monad laws and reinforce the importance of checking the laws. E.g. while Option satisfies the laws, Try is not a lawful Monad: it trades the left identity law for the bullet-proof principle.
* ERRATA *
1) on the first slide the Kleisli composition signature appears three times, but one of the occurrences is incorrect in that it is (>=>)::(a->mb)->(b->mb)->(a->mc) whereas is should be (>=>)::(a->mb)->(b->mc)->(a->mc) - thank you Jules Ivanic.
Exploring Ceylon with Gavin King - JUG BB Talk - Belrin 2014hwilming
The slide to the Java User Group Talk Exploring Ceylon from Gavin King.
Abstrakt:
Ceylon is a new programming language designed for writing large programs in teams. The language emphasizes readability, modularity, typesafety, and tooling. Ceylon programs execute on Java and JavaScript virtual machines. In this session, Gavin King will talk about the ideas behind Ceylon and demonstrate the language, its type system, its module architecture, and its IDE.
Speaker:
Gavin King leads the Ceylon project at Red Hat. He is the creator of Hibernate, a popular object/relational persistence solution for Java, and the Seam Framework, an application framework for enterprise Java. He's contributed to the Java Community Process as JBoss and then Red Hat representative for the EJB and JPA specifications and as lead of the CDI specification.
Now he works full time on Ceylon, polishing the language specification, developing the compiler frontend, and thinking about the SDK and future of the platform. He's still a fan of Java, and of other languages, especially Smalltalk, Python, and ML.
Apple's Swift has achieved the top place in Stack Overflow's "Most Loved" list of programming languages in its 2015 Developer Survey. Based on information gleaned from GitHub and Stack Overflow, analyst firm RedMonk has seen Swift's popularity ranking soar from 68 to 22 in an unprecedented 6 months.
The "Extreme Swift" event does not require advanced, or even any, knowledge of Swift. Learn about some of the more outrageous features of the language which help explain what the fuss is all about!
Never look at programming the same way again — even if you never end up writing a single line of Swift code in your life.
Functional programming is getting a lot of attention because it eases many of the difficulties faced in object-oriented programming (OOP) such as testability, maintainability, scalability, and concurrency. Swift has a lot of functional programming features that can be easily used, but most of Objective-C and Swift programmers are not familiar with these concepts.
This talk aims to introduce some of the core concepts of functional programming with Swift such as:
• Importance of Immutability
• First-class, Higher-order and Pure functions
• Closures
• Generics and Associated Type Protocols
• Functors, Applicative Functors and Monads
• Enumerations and Pattern Matching
• Optionals
Python Homework Help has the best homework help experts for your academic homework. Our Python experts hold Ph.D. degrees and can help you in preparing accurate solutions and answers for your Python homework questions. Our panel of online Python experts will help you get your basics right in order to understand and tackle difficult problems.
Reach out to our team via: -
Website: - https://www.pythonhomeworkhelp.com/
Email: support@pythonhomeworkhelp.com
Call/WhatsApp: +1(507)509–5569
Python Homework Help is quality-oriented and has invested heavily in quality control. We have put together the best team of Python professionals combining talent, creativity, and experience. Our experts can handle every Python homework and ensure the student secures high grades, within their submission deadline. Every homework is plagiarism free and a turn-it-in report is issued at the time of delivery.
Reach out to our team via: -
Website: - https://www.pythonhomeworkhelp.com/
Email: support@pythonhomeworkhelp.com
Call/WhatsApp: +1(507)509–5569
Similar to Ad hoc Polymorphism using Type Classes and Cats (20)
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidPhilip Schwarz
The subject of this deck is the small Print[A] program in the following blog post by Noel Welsh: https://www.inner-product.com/posts/direct-style-effects/.
Keywords: "direct-style", "context function", "context functions", "algebraic effect", "algebraic effects", "scala", "effect system", "effect systems", "effect", "side effect", "composition", "fp", "functional programming"
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
For functions that can be defined both as an instance of a right fold and as an instance of a left fold, one may be more efficient than the other.
Let's look at the example of a function 'decimal' that converts a list of digits into the corresponding decimal number.
Erratum: it has been pointed out that it is possible to define the zip function using a right fold (see slide 5).
Tagless Final Encoding - Algebras and Interpreters and also ProgramsPhilip Schwarz
Tagless Final Encoding - Algebras and Interpreters and also Programs - An introduction, through the work of Gabriel Volpe.
Slide deck home: http://fpilluminated.com/assets/tagless-final-encoding-algebras-interpreters-and-programs.html
A sighting of traverseFilter and foldMap in Practical FP in ScalaPhilip Schwarz
Slide deck home: http://fpilluminated.com/assets/sighting-of-scala-cats-traverseFilter-and-foldMap-in-practical-fp-in-scala.html.
Download PDF for perfect image quality.
A sighting of sequence function in Practical FP in ScalaPhilip Schwarz
Slide deck home: http://fpilluminated.com/assets/sighting-of-scala-cats-sequence-function-in-practical-fp-in-scala.html.
Download PDF for perfect image quality.
This talk was presented on Aug 3rd 2023 during the Scala in the City event a ITV in London https://www.meetup.com/scala-in-the-city/events/292844968/
Visit the following for a description, slideshow, all slides with transcript, pdf, github repo, and eventually a video recording: http://fpilluminated.com/assets/n-queens-combinatorial-puzzle-meets-cats.html
At the centre of this talk is the N-Queens combinatorial puzzle. The reason why this puzzle features in the Scala book and functional programming course by Martin Odersky (the language’s creator), is that such puzzles are a particularly suitable application area of 'for comprehensions'.
We’ll start by (re)acquainting ourselves with the puzzle, and seeing the role played in it by permutations. Next, we’ll see how, when wanting to visualise candidate puzzle solutions, Cats’ monoidal functions fold and foldMap are a great fit for combining images.
While we are all very familiar with the triad providing the bread, butter and jam of functional programming, i.e. map, filter and fold, not everyone knows about the corresponding functions in Cats’ monadic variant of the triad, i.e. mapM, filterM and foldM, which we are going to learn about next.
As is often the case in functional programming, the traverse function makes an appearance, and we shall grab the opportunity to point out the symmetry that exists in the interrelation of flatMap / foldMap / traverse and flatten / fold / sequence.
Armed with an understanding of foldM, we then look at how such a function can be used to implement an iterative algorithm for the N-Queens puzzle.
The talk ends by pointing out that the iterative algorithm is smarter than the recursive one, because it ‘remembers’ where it has already placed previous queens.
Kleisli composition, flatMap, join, map, unit - implementation and interrelat...Philip Schwarz
Kleisli composition, flatMap, join, map, unit. A study/memory aid, to help learn/recall their implementation/interrelation.
Version 2, updated for Scala 3
Nat, List and Option Monoids -from scratch -Combining and Folding -an examplePhilip Schwarz
Nat, List and Option Monoids, from scratch. Combining and Folding: an example.
This is a new version of the original which has some cosmetic changes and a new 7th slide which only differs from slide 6 in that it defines the fold function in terms of the foldRight function.
Code: https://github.com/philipschwarz/nat-list-and-option-monoids-from-scratch-combining-and-folding-an-example
The Sieve of Eratosthenes - Part II - Genuine versus Unfaithful Sieve - Haske...Philip Schwarz
When I posted the deck for Part 1 to the Scala users forum, Odd Möller linked to a paper titled "The Genuine Sieve of Eratosthenes", which speaks of the Unfaithful Sieve.
Part 2 is based on that paper and on Richard Bird's faithful Haskell implementation of the Sieve, which we translate into Scala.
Scala code for Richard Bird's infinite primes Haskell program: https://github.com/philipschwarz/sieve-of-eratosthenes-part-2-scala
Jordan Peterson - The pursuit of meaning and related ethical axiomsPhilip Schwarz
I have only recently become aware of the work of Jordan Peterson. Because I am finding it so interesting, I hope that the following small collection of excerpts from some of his writings and speeches might entice any fellow latecomers to find out more about his work. See below for my own summary of some of the subjects touched upon in these slides.
Download for best results.
Defining filter using (a) recursion (b) folding (c) folding with S, B and I c...Philip Schwarz
Defining filter using
(a) recursion
(b) folding
(c) folding with S, B and I combinators
(d) folding with applicative functor and identity function.pdf
This second version adds a simpler folding definition, which I had left out in the first version.
The Sieve of Eratosthenes - Part 1 - with minor correctionsPhilip Schwarz
In this slide deck we are going to see some examples of how the effort required to read an understand the Sieve of Eratosthenes varies greatly depending on the programming paradigm used to implement the algorithm.
We'll see code in Java, Scheme, Haskell and Scala.
This version of the deck contains some minor corrections (see errata section in first version for details)
Enhancing Research Orchestration Capabilities at ORNL.pdfGlobus
Cross-facility research orchestration comes with ever-changing constraints regarding the availability and suitability of various compute and data resources. In short, a flexible data and processing fabric is needed to enable the dynamic redirection of data and compute tasks throughout the lifecycle of an experiment. In this talk, we illustrate how we easily leveraged Globus services to instrument the ACE research testbed at the Oak Ridge Leadership Computing Facility with flexible data and task orchestration capabilities.
Top 7 Unique WhatsApp API Benefits | Saudi ArabiaYara Milbes
Discover the transformative power of the WhatsApp API in our latest SlideShare presentation, "Top 7 Unique WhatsApp API Benefits." In today's fast-paced digital era, effective communication is crucial for both personal and professional success. Whether you're a small business looking to enhance customer interactions or an individual seeking seamless communication with loved ones, the WhatsApp API offers robust capabilities that can significantly elevate your experience.
In this presentation, we delve into the top 7 distinctive benefits of the WhatsApp API, provided by the leading WhatsApp API service provider in Saudi Arabia. Learn how to streamline customer support, automate notifications, leverage rich media messaging, run scalable marketing campaigns, integrate secure payments, synchronize with CRM systems, and ensure enhanced security and privacy.
Globus Connect Server Deep Dive - GlobusWorld 2024Globus
We explore the Globus Connect Server (GCS) architecture and experiment with advanced configuration options and use cases. This content is targeted at system administrators who are familiar with GCS and currently operate—or are planning to operate—broader deployments at their institution.
Check out the webinar slides to learn more about how XfilesPro transforms Salesforce document management by leveraging its world-class applications. For more details, please connect with sales@xfilespro.com
If you want to watch the on-demand webinar, please click here: https://www.xfilespro.com/webinars/salesforce-document-management-2-0-smarter-faster-better/
May Marketo Masterclass, London MUG May 22 2024.pdfAdele Miller
Can't make Adobe Summit in Vegas? No sweat because the EMEA Marketo Engage Champions are coming to London to share their Summit sessions, insights and more!
This is a MUG with a twist you don't want to miss.
We describe the deployment and use of Globus Compute for remote computation. This content is aimed at researchers who wish to compute on remote resources using a unified programming interface, as well as system administrators who will deploy and operate Globus Compute services on their research computing infrastructure.
Essentials of Automations: The Art of Triggers and Actions in FMESafe Software
In this second installment of our Essentials of Automations webinar series, we’ll explore the landscape of triggers and actions, guiding you through the nuances of authoring and adapting workspaces for seamless automations. Gain an understanding of the full spectrum of triggers and actions available in FME, empowering you to enhance your workspaces for efficient automation.
We’ll kick things off by showcasing the most commonly used event-based triggers, introducing you to various automation workflows like manual triggers, schedules, directory watchers, and more. Plus, see how these elements play out in real scenarios.
Whether you’re tweaking your current setup or building from the ground up, this session will arm you with the tools and insights needed to transform your FME usage into a powerhouse of productivity. Join us to discover effective strategies that simplify complex processes, enhancing your productivity and transforming your data management practices with FME. Let’s turn complexity into clarity and make your workspaces work wonders!
Climate Science Flows: Enabling Petabyte-Scale Climate Analysis with the Eart...Globus
The Earth System Grid Federation (ESGF) is a global network of data servers that archives and distributes the planet’s largest collection of Earth system model output for thousands of climate and environmental scientists worldwide. Many of these petabyte-scale data archives are located in proximity to large high-performance computing (HPC) or cloud computing resources, but the primary workflow for data users consists of transferring data, and applying computations on a different system. As a part of the ESGF 2.0 US project (funded by the United States Department of Energy Office of Science), we developed pre-defined data workflows, which can be run on-demand, capable of applying many data reduction and data analysis to the large ESGF data archives, transferring only the resultant analysis (ex. visualizations, smaller data files). In this talk, we will showcase a few of these workflows, highlighting how Globus Flows can be used for petabyte-scale climate analysis.
Understanding Globus Data Transfers with NetSageGlobus
NetSage is an open privacy-aware network measurement, analysis, and visualization service designed to help end-users visualize and reason about large data transfers. NetSage traditionally has used a combination of passive measurements, including SNMP and flow data, as well as active measurements, mainly perfSONAR, to provide longitudinal network performance data visualization. It has been deployed by dozens of networks world wide, and is supported domestically by the Engagement and Performance Operations Center (EPOC), NSF #2328479. We have recently expanded the NetSage data sources to include logs for Globus data transfers, following the same privacy-preserving approach as for Flow data. Using the logs for the Texas Advanced Computing Center (TACC) as an example, this talk will walk through several different example use cases that NetSage can answer, including: Who is using Globus to share data with my institution, and what kind of performance are they able to achieve? How many transfers has Globus supported for us? Which sites are we sharing the most data with, and how is that changing over time? How is my site using Globus to move data internally, and what kind of performance do we see for those transfers? What percentage of data transfers at my institution used Globus, and how did the overall data transfer performance compare to the Globus users?
Code reviews are vital for ensuring good code quality. They serve as one of our last lines of defense against bugs and subpar code reaching production.
Yet, they often turn into annoying tasks riddled with frustration, hostility, unclear feedback and lack of standards. How can we improve this crucial process?
In this session we will cover:
- The Art of Effective Code Reviews
- Streamlining the Review Process
- Elevating Reviews with Automated Tools
By the end of this presentation, you'll have the knowledge on how to organize and improve your code review proces
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteGoogle
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
👉👉 Click Here To Get More Info 👇👇
https://sumonreview.com/ai-pilot-review/
AI Pilot Review: Key Features
✅Deploy AI expert bots in Any Niche With Just A Click
✅With one keyword, generate complete funnels, websites, landing pages, and more.
✅More than 85 AI features are included in the AI pilot.
✅No setup or configuration; use your voice (like Siri) to do whatever you want.
✅You Can Use AI Pilot To Create your version of AI Pilot And Charge People For It…
✅ZERO Manual Work With AI Pilot. Never write, Design, Or Code Again.
✅ZERO Limits On Features Or Usages
✅Use Our AI-powered Traffic To Get Hundreds Of Customers
✅No Complicated Setup: Get Up And Running In 2 Minutes
✅99.99% Up-Time Guaranteed
✅30 Days Money-Back Guarantee
✅ZERO Upfront Cost
See My Other Reviews Article:
(1) TubeTrivia AI Review: https://sumonreview.com/tubetrivia-ai-review
(2) SocioWave Review: https://sumonreview.com/sociowave-review
(3) AI Partner & Profit Review: https://sumonreview.com/ai-partner-profit-review
(4) AI Ebook Suite Review: https://sumonreview.com/ai-ebook-suite-review
Cyaniclab : Software Development Agency Portfolio.pdfCyanic lab
CyanicLab, an offshore custom software development company based in Sweden,India, Finland, is your go-to partner for startup development and innovative web design solutions. Our expert team specializes in crafting cutting-edge software tailored to meet the unique needs of startups and established enterprises alike. From conceptualization to execution, we offer comprehensive services including web and mobile app development, UI/UX design, and ongoing software maintenance. Ready to elevate your business? Contact CyanicLab today and let us propel your vision to success with our top-notch IT solutions.
Utilocate offers a comprehensive solution for locate ticket management by automating and streamlining the entire process. By integrating with Geospatial Information Systems (GIS), it provides accurate mapping and visualization of utility locations, enhancing decision-making and reducing the risk of errors. The system's advanced data analytics tools help identify trends, predict potential issues, and optimize resource allocation, making the locate ticket management process smarter and more efficient. Additionally, automated ticket management ensures consistency and reduces human error, while real-time notifications keep all relevant personnel informed and ready to respond promptly.
The system's ability to streamline workflows and automate ticket routing significantly reduces the time taken to process each ticket, making the process faster and more efficient. Mobile access allows field technicians to update ticket information on the go, ensuring that the latest information is always available and accelerating the locate process. Overall, Utilocate not only enhances the efficiency and accuracy of locate ticket management but also improves safety by minimizing the risk of utility damage through precise and timely locates.
How to Position Your Globus Data Portal for Success Ten Good PracticesGlobus
Science gateways allow science and engineering communities to access shared data, software, computing services, and instruments. Science gateways have gained a lot of traction in the last twenty years, as evidenced by projects such as the Science Gateways Community Institute (SGCI) and the Center of Excellence on Science Gateways (SGX3) in the US, The Australian Research Data Commons (ARDC) and its platforms in Australia, and the projects around Virtual Research Environments in Europe. A few mature frameworks have evolved with their different strengths and foci and have been taken up by a larger community such as the Globus Data Portal, Hubzero, Tapis, and Galaxy. However, even when gateways are built on successful frameworks, they continue to face the challenges of ongoing maintenance costs and how to meet the ever-expanding needs of the community they serve with enhanced features. It is not uncommon that gateways with compelling use cases are nonetheless unable to get past the prototype phase and become a full production service, or if they do, they don't survive more than a couple of years. While there is no guaranteed pathway to success, it seems likely that for any gateway there is a need for a strong community and/or solid funding streams to create and sustain its success. With over twenty years of examples to draw from, this presentation goes into detail for ten factors common to successful and enduring gateways that effectively serve as best practices for any new or developing gateway.
Software Engineering, Software Consulting, Tech Lead.
Spring Boot, Spring Cloud, Spring Core, Spring JDBC, Spring Security,
Spring Transaction, Spring MVC,
Log4j, REST/SOAP WEB-SERVICES.
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus
As part of the DOE Integrated Research Infrastructure (IRI) program, NERSC at Lawrence Berkeley National Lab and ALCF at Argonne National Lab are working closely with General Atomics on accelerating the computing requirements of the DIII-D experiment. As part of the work the team is investigating ways to speedup the time to solution for many different parts of the DIII-D workflow including how they run jobs on HPC systems. One of these routes is looking at Globus Compute as a way to replace the current method for managing tasks and we describe a brief proof of concept showing how Globus Compute could help to schedule jobs and be a tool to connect compute at different facilities.
Prosigns: Transforming Business with Tailored Technology SolutionsProsigns
Unlocking Business Potential: Tailored Technology Solutions by Prosigns
Discover how Prosigns, a leading technology solutions provider, partners with businesses to drive innovation and success. Our presentation showcases our comprehensive range of services, including custom software development, web and mobile app development, AI & ML solutions, blockchain integration, DevOps services, and Microsoft Dynamics 365 support.
Custom Software Development: Prosigns specializes in creating bespoke software solutions that cater to your unique business needs. Our team of experts works closely with you to understand your requirements and deliver tailor-made software that enhances efficiency and drives growth.
Web and Mobile App Development: From responsive websites to intuitive mobile applications, Prosigns develops cutting-edge solutions that engage users and deliver seamless experiences across devices.
AI & ML Solutions: Harnessing the power of Artificial Intelligence and Machine Learning, Prosigns provides smart solutions that automate processes, provide valuable insights, and drive informed decision-making.
Blockchain Integration: Prosigns offers comprehensive blockchain solutions, including development, integration, and consulting services, enabling businesses to leverage blockchain technology for enhanced security, transparency, and efficiency.
DevOps Services: Prosigns' DevOps services streamline development and operations processes, ensuring faster and more reliable software delivery through automation and continuous integration.
Microsoft Dynamics 365 Support: Prosigns provides comprehensive support and maintenance services for Microsoft Dynamics 365, ensuring your system is always up-to-date, secure, and running smoothly.
Learn how our collaborative approach and dedication to excellence help businesses achieve their goals and stay ahead in today's digital landscape. From concept to deployment, Prosigns is your trusted partner for transforming ideas into reality and unlocking the full potential of your business.
Join us on a journey of innovation and growth. Let's partner for success with Prosigns.
Launch Your Streaming Platforms in MinutesRoshan Dwivedi
The claim of launching a streaming platform in minutes might be a bit of an exaggeration, but there are services that can significantly streamline the process. Here's a breakdown:
Pros of Speedy Streaming Platform Launch Services:
No coding required: These services often use drag-and-drop interfaces or pre-built templates, eliminating the need for programming knowledge.
Faster setup: Compared to building from scratch, these platforms can get you up and running much quicker.
All-in-one solutions: Many services offer features like content management systems (CMS), video players, and monetization tools, reducing the need for multiple integrations.
Things to Consider:
Limited customization: These platforms may offer less flexibility in design and functionality compared to custom-built solutions.
Scalability: As your audience grows, you might need to upgrade to a more robust platform or encounter limitations with the "quick launch" option.
Features: Carefully evaluate which features are included and if they meet your specific needs (e.g., live streaming, subscription options).
Examples of Services for Launching Streaming Platforms:
Muvi [muvi com]
Uscreen [usencreen tv]
Alternatives to Consider:
Existing Streaming platforms: Platforms like YouTube or Twitch might be suitable for basic streaming needs, though monetization options might be limited.
Custom Development: While more time-consuming, custom development offers the most control and flexibility for your platform.
Overall, launching a streaming platform in minutes might not be entirely realistic, but these services can significantly speed up the process compared to building from scratch. Carefully consider your needs and budget when choosing the best option for you.
First Steps with Globus Compute Multi-User EndpointsGlobus
In this presentation we will share our experiences around getting started with the Globus Compute multi-user endpoint. Working with the Pharmacology group at the University of Auckland, we have previously written an application using Globus Compute that can offload computationally expensive steps in the researcher's workflows, which they wish to manage from their familiar Windows environments, onto the NeSI (New Zealand eScience Infrastructure) cluster. Some of the challenges we have encountered were that each researcher had to set up and manage their own single-user globus compute endpoint and that the workloads had varying resource requirements (CPUs, memory and wall time) between different runs. We hope that the multi-user endpoint will help to address these challenges and share an update on our progress here.
2. The talk is going to focus on, firstly, subtype polymorphism, the classic OOP approach to functionality and stuff, and
we are going to move from that, we are going to show that briefly, and then we are going to change it to ad hoc
polymorphism using type classes.
And we are going to do this all in the scope of sorting, sorting a list of something, in this case Ints, but your humble
sort function, so it should be familiar ground for most people.
And it is all going to be live coding, as well, so I have definitely set myself up for failure on my first talk, but wish me
luck.
def sortInts(ls: List[Int]): List[Int]
Monty West
https://www.linkedin.com/in/monty-west/
Ok, so, first of all, five points for whoever can name the sort.
Yes, Quicksort. So I have this sort, it just sorts Ints, kind of useful, but I have this new class that I want to use, in a
List say, a Person class, and I have defined this myself.
So how do I sort Persons?
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
}
final case class Person(age: Int, name: String)
3. Monty West
Obviously we could just define a sort function for persons, but it wouldn’t be useful for anything else so as we are all
good programmers, we want to be more generic, we want to be able to apply this sort function to an A, an A type.
So this kind of looks like this:
Done, right? Finished, great! So not quite: we don’t know how to compare As together, we don’t have this less than
operation. We don’t have anything like that. The compiler doesn’t know what A is, it can’t infer that.
4. Monty West
https://www.linkedin.com/in/monty-west/
So how would we approach this in a sort of subtype polymorphism way?
Well, the first thing we do is we add an interface, so I am going to add a trait. I am going to call it
Orderable, and the intention of this trait is to be a supertype of whatever we want to order. So in
this case it is going to be As but we’ll add it to the Person class, and what it needs to be able to do is
compare to another instance of A…
I am also going to have a quick helper because we saw it just there, we are going to add a less than
function as well, and it is just going to return a Boolean, and that is going to just use our compare
function.
That should be familiar. That’s pretty much how the Comparable interface in Java works.
trait Orderable[A] {
/**
* this < other : negative
* this = other : 0
* this > other : positive
*
* @param other
* @return
*/
def compare(other: A): Int
def <(other: A): Boolean = compare(other) < 0
}
5. Monty West
So we are going to use this in our sort.
we import Orderable and we introduce a type bound for our A
And that should compile, so now, anything that is Orderable can be sorted by this function.
6. Monty West
https://www.linkedin.com/in/monty-west/
So we have to make our Person class Orderable and we do that by extending and implementing
Orderable:
We have a choice to make here about how we sort Persons. I am just going to choose age because it
is the easiest one to use but it is noteworthy that we have to make a choice, we have to define the
way we want to order Persons and put it on the actual class.
So in this case it is going to be this:
The other thing to notice here is that we use ‘this’, this is how we compare two things, we have access
to our current and then we have another one passed into this function.
final case class Person(age: Int, name: String) extends Orderable[Person] {
/**
* this < other : negative
* this = other : 0
* this > other : positive
*
* @param other
* @return
*/
override def compare(other: Person): Int = ???
}
override def compare(other: Person): Int = this.age - other.age
7. sbt:tech_talk-typeclass> run
@ personLs
res0: List[Person] = List(Person(23, "alice"), Person(35, "bob"), Person(21, "charlie"))
@
Welcome to the Ammonite Repl 1.6.3e-cats / Compile / compileIncremental 0s
(Scala 2.12.8 Java 1.8.0_112)
If you like Ammonite, please support our development at www.patreon.com/lihaoyi
@
@ ops.sort(personLs)
res1: List[Person] = List(Person(21, "charlie"), Person(23, "alice"), Person(35, "bob"))
@
OK, so let’s actually use this, let’s hope this all compiles. So I am going to run.
so I have pre-prepared a list of persons hereMonty West
and now I can call my sort function with this list and it should sort them
Cool, job done.
8. Monty West
https://www.linkedin.com/in/monty-west/
So the problem here is that I also have an Int List and say I want to sort that, I want to use my
generic sort because I only want to maintain one function and obviously I can’t do that because Int
is not implementing my interface and if I pass it in it will give me a big error:
So that’s not great and also we can’t go and fix this. We can’t go into the Int class of Scala/Java and
add this Orderable trait and implement it. We don’t really have any option to, we can’t order Ints.
The other thing is, if we want to change the sort of Persons, if we want to sort by name for
example, or if we want to reverse the sort, we have to actually go into the implementation of
Person and change that comparison function, which is annoying, to have to go all the way down
into our actual class that’s just holding data and change something.
@ ops.sort(intLs)
cmd2.sc:1: inferred type arguments [Int] do not conform to method sort's type
parameter bounds [A <: mw.domain.Orderable[A]]
val res2 = ops.sort(intLs)
^
cmd2.sc:1: type mismatch;
found : List[Int]
required: List[A]
val res2 = ops.sort(intLs)
^
Compilation Failed
@
final case class Person(age: Int, name: String)
extends Orderable[Person] {
/**
* this < other : negative
* this = other : 0
* this > other : positive
*
* @param other
* @return
*/
override def compare(other: Person): Int =
this.age - other.age
}
9. import mw.domain.Orderable
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A <: Orderable[A]](ls: List[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
}
trait Orderable[A] {
/**
* this < other : negative
* this = other : 0
* this > other : positive
*
* @param other
* @return
*/
def compare(other: A): Int
def <(other: A): Boolean = compare(other) < 0
}
final case class Person(age: Int, name: String) extends Orderable[Person] {
/**
* this < other : negative
* this = other : 0
* this > other : positive
*
* @param other
* @return
*/
override def compare(other: Person): Int = this.age - other.age
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
@philip_schwarz
Recap - Version 1 of
the code: Subtype
Polymorphism
@ ops.sort(personLs)
10. Monty West
So, what can we do about it?
This is where I am going to introduce type classes and ad hoc polymorphism.
So I am just going to delete all that . So let’s go all of the way back to when we
had this, this sort of like failed generic sort with nothing on it.
11. package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
}
final case class Person(age: Int, name: String)
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
@philip_schwarz
Recap - back to an
intermediate version of
the code with a generic
sort that doesn’t
compile.
12. So I am going to reintroduce the Orderable trait, with some slight differences.
So instead of just taking one other of whatever, I am trying to compare, it is going to take two, it is going to take both in, so
it is going to look like this, I won’t write that comment again, that took too long, and I will also put the less than on just for
our sort function:
So very similar to last time. This time we are passing in both parameters. The intention here is that this won’t be
implemented by our Person class, so we won’t have access to ‘this’, so we have to pass them both in.
trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
trait Orderable[A] {
/**
* this < other : negative
* this = other : 0
* this > other : positive
*
* @param other
* @return
*/
def compare(other: A): Int
def <(other: A): Boolean = compare(other) < 0
}
Monty West
13. Monty West
So how are we going to use this Orderable trait in our sort function?
So we don’t. Our A is not going to be a Orderable any more, we are not going to get that for free from our A, so the
only option we really have is to pass this in explicitly, so we are going to need some instance of this class, in order to
use it, and we are going to pass it in a separate parameter list.
And also, we don’t get this nice syntax anymore, we are going to have to do something like this, which is a bit clunky
and also, this is still not compiling…
15. Monty West
https://www.linkedin.com/in/monty-west/
The next stage is to somehow create this Orderable instance for Person.
This isn’t going to be a supertype of Person, in fact we don’t need to change the Person class at all.
You just need somewhere else where you put an instance of this thing. A common place to see such
instances is in the companion object of Person and this will be relevant later when we start
introducing implicits, so I am just going to do that for now and I am going to explain why later. I am just
going to put in a val and call it personOrderable, and now we just need to implement this interface,
so we are going to do the same we did last time, we are going to use age, so it is going to be left age
minus right age:
And this all compiles.
16. Welcome to the Ammonite Repl 1.6.3
(Scala 2.12.8 Java 1.8.0_112)
If you like Ammonite, please support our development at www.patreon.com/lihaoyi
@ personLs
res0: List[Person] = List(Person(23, "alice"), Person(35, "bob"), Person(21, "charlie"))
@
sbt:tech_talk-typeclass> run
@ ops.sort(personLs)(Person.personOrderable)
res1: List[Person] = List(Person(21, "charlie"), Person(23, "alice"), Person(35, "bob"))
@
@ ops.sort(intLs)(???)
So now we are able to go back to our shell and do exactly what we did last time.
there it is, and hopefully we should be able to do what we did last time,
and sort persons, but we need to pass in this instance. So it’s a bit clunky,
Monty West
There we go, that sorts nicely. So we’ve got the sort, and we’ve removed the subtyping part,
but we’ve changed the call site signature, it’s a bit clunky now, you have to remember
where things are, we still can’t sort Ints, we don’t have an instance to put here:
OK, so we have out person list
18. final case class Person(age: Int, name: String)
trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
import mw.domain.Orderable
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A])(order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => order.<(a,x)))(order) ++ List(x) ++ sort(xs.filterNot(a => order.<(a,x)))(order)
}
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
final case class Person(age: Int, name: String)
object Person {
val personOrderable: Orderable[Person] = new Orderable[Person] {
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
@ ops.sort(personLs)(Person.personOrderable)
@philip_schwarz
Recap - Version 2 – same as Version 1, but potentially worse. Clunky call site and nastiness in the syntax of the sort function.
19. The first thing I want to address is this call site problem. How can we get around passing this thing explicitly, and
that’s the clue I suppose. I am going to introduce some implicits here.
So in our sort function, I am going to make this second parameter list implicit
And this does two things for us, it allows for the Orderable instance to be passed in implicitly, so from implicit scope,
wherever you are calling it from. It also means it is added to the implicit scope of this function, so we no longer need
this second parameter list here:
And everything will still compile.
Monty West
20. So if we run this again we’ll see that we can just sort persons exactly like we did with
subtype polymorphism with no extra like additions to the call.
Monty West
And in order to make these Orderable instances available in implicit scope, we
can make them implicit where they are defined. So we can make this val implicit:
Because of implicit magic this all works right, don’t worry, I will explain.
Like that. So the reason this works is that one of the places where it
will look for implicits when it is trying to find one is the companion
object of the A, of the class that is parameterising the function.
@ ops.sort(personLs)
res0: List[Person] = List(Person(21, "charlie"), Person(23, "alice"), Person(35, "bob"))
@
def sort[A](ls: List[A])
(implicit order: Orderable[A]): List[A]
21. trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = new Orderable[Person] {
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
import mw.domain.Orderable
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => order.<(a,x))) ++ List(x) ++ sort(xs.filterNot(a => order.<(a,x)))
}
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
@ ops.sort(personLs)
@philip_schwarz
Recap - Version 2b – Using implicit personOrderable
22. Monty West
https://www.linkedin.com/in/monty-west/
That’s one problem out of the way. We’ve got the call site back as in subtype polymorphism and we are
probably like equal now, interfaces, in terms of whoever is using this.
So is there any advantage of this approach?
Well the first one is that we can use our generic sort for Ints now, even though we don’t own the Int
class, we can define an instance, we didn’t have to change Person, so now we can do the same for Int.
Obviously, because we don’t own the Int class, we can’t add a companion object of Int, so one place
you’ll commonly see this is in, if you do own the type class itself, you’ll see this on the companion
object of the type class. And again we are going to make it implicit.
@ ops.sort(personLs)
24. trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
object Orderable {
implicit val intOrderable: Orderable[Int] = new Orderable[Int] {
override def compare(l: Int, r: Int): Int = l - r
}
}
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = new Orderable[Person] {
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
import mw.domain.Orderable
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => order.<(a,x))) ++ List(x) ++ sort(xs.filterNot(a => order.<(a,x)))
}
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
@ ops.sort(intLs)@ ops.sort(personLs)
@philip_schwarz
Recap - Version 2c
Using implicit
personOrderable
and implicit
intOrderable.
25. Monty West
Cool. So where have we got to? Ah, it’s worth noting that if you don’t own the typeclass itself, if you don’t own this
trait, then you can’t obviously add it to the companion object of the trait, so occasionally you will see something like
this, where you have to define an instance for something you don’t own, with a typeclass that you also don’t own. And
sometimes you’ll see this in an instances package with a companion object, I just thought I’d quickly show you that,
package object instances {
implicit val intOrderable: Orderable[Int] = new Orderable[Int] {
override def compare(l: Int, r: Int): Int = l - r
}
}
@ intLs
res0: List[Int] = List(-5, 8, 10, 2, 5)
@
@ ops.sort(intLs)
cmd1.sc:1: could not find implicit value for parameter order: mw.domain.Orderable[Int]
val res1 = ops.sort(intLs)
^
Compilation Failed
@
Welcome to the Ammonite Repl 1.6.3e-cats / Compile / compileIncremental 0s
(Scala 2.12.8 Java 1.8.0_112)
If you like Ammonite, please support our development at www.patreon.com/lihaoyi
@
And we can still do what we did before, but there is a slight gotcha here, I’ll just quickly show. So we’ve still got our Int List
And if we call our sort function, everything should work, everything implicit magic correct, so no:
The reason is that we haven’t
imported this instances package.
So we don’t have this nice
companion object automatically
found by the implicit resolution.
27. trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
import mw.domain.Orderable
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => order.<(a,x))) ++ List(x) ++ sort(xs.filterNot(a => order.<(a,x)))
}
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
package object instances {
implicit val intOrderable: Orderable[Int] = new Orderable[Int] {
override def compare(l: Int, r: Int): Int = l - r
}
}
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = new Orderable[Person] {
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
@ import mw.domain.instances._
import mw.domain.instances._
@ ops.sort(intLs)
@ ops.sort(personLs)
@philip_schwarz
Recap - Version 2d – still using implicit personOrderable and implicit intOrderable, even if not owning Orderable
28. Monty West
What we have done here is something that is quite common in FP generally, which is, we have taken a concept, such as
subtype polymorphism, and we turned it into a value. And the benefit we gain from that is a higher level of abstraction,
we can now take these values and we can compose them, we can transform them, we can create new values. And that can
unlock quite a nice level of abstraction as I said, and also, reduce some of this boilerplate, we can get some nice
functionality out of it.
So the first one I want to talk about is what if we want to reverse the order of any of these? So in our Orderable trait,
what if we want to reverse an order? How can we go about that? Does this approach do this better than subtype
polymorphism?
So what we can do is we can take an Orderable instance in a function and we can transform it and we can return it out the
other side. And we can do that to provide some kind of reverse functionality. So if I define this function, and it is going to
take in an Orderable and it is going to take it in implicitly and it is going to spit out an Orderable. And this is suprisingly
easy to define. We have this orderable for A already, so we just have to compare them in the opposite order.
so this will take a sort and reverse that sort, return an instance that does the reverse sort of what we passed in, implicitly.
29. Monty West
So how can we use this? We don’t need to make any changes
anywhere else. If we go back to the shell, so our person list
Welcome to the Ammonite Repl 1.6.3
(Scala 2.12.8 Java 1.8.0_112)
If you like Ammonite, please support our development at www.patreon.com/lihaoyi
@ personLs
res0: List[Person] = List(Person(23, "alice"), Person(35, "bob"), Person(21, "charlie"))
@
@ ops.sort(personLs)
res1: List[Person] = List(Person(21, "charlie"), Person(23, "alice"), Person(35, "bob"))
@
so if I sort the normal way, as defined in the
personOrderable instance, we get this way.
And now I can do two different ways of applying this reverse. I can do, because the sort function
still has this second parameter list, even though it is implicit, we can pass it in explicitly
30. So this is me passing it in explicitly. What is happening is that this reverse function itself finds the
initial person orderable and just … and … another one that is explicitly passed in. So there is some
interesting resolution here but not at the sort of function level, at the Orderable reverse.
@ ops.sort(personLs)(Orderable.reverse)
res2: List[Person] = List(Person(35, "bob"), Person(23, "alice"), Person(21, "charlie"))
@
@ implicit val reverse: Orderable[Person] = Orderable.reverse
reverse: Orderable[Person] = mw.domain.Orderable$$anon$1@610dd9c4
@
@ ops.sort(personLs)
java.lang.NullPointerException
mw.domain.Orderable$$anon$1.compare(Orderable.scala:26)
…
And that has reversed the order. The other way we can do reverse is in this scope, we
can override that implicit. So if we define an implicit value here, let’s call it reverse.
And the type inference in Scala will be clever enough to know that I want the reverse of a Person, just by
the type parameter on the actual value. And now if I call just normal sort person, it will have the reverse.
Oh, not quite …<comment from audience>… ah ok, I’ll skip that for
now, but you can do that, I have obviously just forgotten how to.
Monty West
31. trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
object Orderable {
implicit val intOrderable: Orderable[Int] = (l: Int, r: Int) => l - r
def reverse[A](implicit order: Orderable[A]): Orderable[A] = new Orderable[A] {
override def compare(l: A, r: A): Int = order.compare(r, l)
}
}
import mw.domain.Orderable
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => order.<(a,x))) ++ List(x) ++ sort(xs.filterNot(a => order.<(a,x)))
}
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = new Orderable[Person] {
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
@ ops.sort(personLs) @ ops.sort(personLs)(Orderable.reverse)
@philip_schwarz
Recap - Version 2e -
reversing an ordering
32. Monty West
https://www.linkedin.com/in/monty-west/
So, something else we can do is, so the slight problem here is this boilerplate
it is annoying. This whole like create a new instance every time. What we can do instead of that is
take an orderable instance of something that we know how to order and then transform it into
something that we don’t know how to order yet. So how about this? I’ll explain in a second.
So we know how to order Bs, we have an instance for this Orderable[B], and we have a function
that takes us from the thing we want to be able to order to that B. And again, this is pretty easy to
implement. We take our Orderable instance for B and we apply that function to each A that we
passed in:
What this allows us to do is reduce a lot of boilerplate and also make our code very readable.
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = new Orderable[Person] {
/** *
* l < r : negative
* l = r : zero
* l > r : positive
*/
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
def by[A,B](f: A => B)(implicit order: Orderable[B]): Orderable[A]
override def compare(l: A, r: A): Int = order.compare(f(l), f(r))
33. So if we go back to our Person class, we know how to order Ints, we have seen Ints
already, so instead of this
And that compiles, because we know how
to sort Ints, that is available on the
Orderable companion object in implicit
scope, and now we are just saying we
want to order persons by age and we
already know how to sort ints so we don’t
need to redefine them.
Monty West now we would just call Orderable.by, and this takes a function,
so I am going to take a person and I am going to pull off the age
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = new Orderable[Person] {
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] =
Orderable.by(person => person.age)(intOrderable)
}
object Orderable {
implicit val intOrderable: Orderable[Int] = …
…
def by[A,B](f: A => B)(implicit order: Orderable[B]): Orderable[A] = new Orderable[A] {
override def compare(l: A, r: A): Int = order.compare(f(l), f(r))
}
}
A = Person; B = Int
object Orderable {
implicit val intOrderable: Orderable[Int] =
(l: Int, r: Int) => l - r
…
}
34. Monty West
And also if we use a bit more Scala sugar here this becomes really readable right?
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = Orderable.by(_.age)
}
Orderable by age. It’s great.
If we then go back and we create an Orderable instance for String, just use the Java or what ever Scala does:
implicit val stringOrderable: Orderable[String] =
(l: String, r: String) => l.compareTo(r)
Then we can show how we can change a sort on the fly. Again start with a person list.
@ personLs
res0: List[Person] = List(Person(23, "alice"), Person(35, "bob"), Person(21, "charlie"))
@
So if we want to sort by name, just in this scope, just for this bit, we have a default sort that does by age, that
we defined in the Person class, but instead we want to sort by name for some reason,
@ implicit val nameOrderable: Orderable[Person] = Orderable.by(_.name)
nameOrderable: Orderable[Person] = mw.domain.Orderable$$anon$2@6041e4ac
@ ops.sort(personLs)
res2: List[Person] = List(Person(23, "alice"), Person(35, "bob"), Person(21, "charlie"))
That was sorted by name rather than by age. So we are able to change the way we use these
type classes, choose the implementation, in the scope that we want to call it on, which again we
would not be able to do with subtype polymorphism. We can change things on the fly. It may
not be the best example here, because I don’t know why you would really want to change that
sort often, but this can be very useful, this extra functionality over subtype polymorphism.
35. trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
object Orderable {
implicit val intOrderable: Orderable[Int] = (l: Int, r: Int) => l - r
implicit val stringOrderable: Orderable[String] = (l: String, r: String) => l.compareTo(r)
def reverse[A](implicit order: Orderable[A]): Orderable[A] = new Orderable[A] {
override def compare(l: A, r: A): Int = order.compare(r, l)
}
def by[A,B](f: A => B)(implicit order: Orderable[B]): Orderable[A] = new Orderable[A] {
override def compare(l: A, r: A): Int = order.compare(f(l), f(r))
}
}
import mw.domain.Orderable
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => order.<(a,x))) ++ List(x) ++ sort(xs.filterNot(a => order.<(a,x)))
}
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] =
Orderable.by(person => person.age)
}
@ implicit val nameOrderable: Orderable[Person] = Orderable.by(_.name)
@ ops.sort(personLs)
@philip_schwarz
Recap - Version 2f
Orderable instance
creation without
boilerplate and on
the fly.
36. Monty West
https://www.linkedin.com/in/monty-west/
So the last problem we have is that our sort function itself is quite clunky. We’ve got this second parameter list,
we’ve got this horrible syntax here with order, is there anything we can do about this?
Can we make it nicer to use these type classes? And yes, the good news there is that we can.
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sort(xs.filter(a => order.<(a, x))) ++ List(x) ++ sort(xs.filterNot(a => order.<(a, x)))
}
}
37. Monty West
So the first thing I’ll address is the syntax. What you’ll sometimes see is a syntax package.
And now I’ll have a package object, and we are going to use an implicit class, I think this pattern has a name, I think it is one of those
things in Scala that draws people in from Java, I think it is called pimp my library pattern or something similar, but we are going to use an
implicit class, and this will wrap any instance of A that we have an Orderable instance for, and allow us to add functions to it, so we
get that nice syntax we saw before.
So we are going to call this OrderableSyntax, and this is going to wrap a value A, but only if we have an Orderable instance for that A.
And the function we want is this less than. Now this sort of looks like our original subtype polymorphism where we just had an ‘other’
and a ‘this’, except that ‘this’ is passed in sort of explicitly and the class wraps around it
OK, so now if we go back to our sort
and we remember to import this, now we can us this nice syntax.
package object syntax {
implicit class OrderableSyntax[A](a: A)(implicit order:Orderable[A]) {
def <(other: A): Boolean = order.<(a, other)
}
}
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sort(xs.filter(a => order.<(a, x))) ++ List(x) ++ sort(xs.filterNot(a => order.<(a, x)))
}
import mw.domain.syntax._
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
38. Monty West
import mw.domain.syntax._
def sort[A](ls: List[A])(implicit order: Orderable[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
This is starting to look a bit more like what we had before, this nice sort of, use of
these type classes can get back to the stage where it feels a lot like using
subtype polymorphism and the niceties you have there.
So the other thing we can do is we can get rid of this second parameter list. And there is
some Scala sugar that allows us to do this, and it’s called a context bound, and again it
looks a bit like a type bound, there is no arrow there, and we are not passing, there is no
like type parameter, but what this will do is this will find the Orderable instances for A
and add them to the implicit scope.
def sort[A: Orderable](ls: List[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
}
What it won’t do is give you an explicit value to call, so for example it seems pretty
obvious but we don’t have an order anymore, that doesn’t exist, but luckily we don’t
need it because we are not calling that explicitly, but there will be times in which you
need the instance to do something with, and to get around this and to keep this nice
sugar we can add something called a summoner.
Replacing an implicit
Orderable[A]
parameter with a
context bound for
Orderable
40. @philip_schwarz
Recap - Version 2g
• Use context bound to
get rid of 2nd
parameter list
• use implicit syntax
class to get rid of
horrible syntax
import mw.domain.Orderable
import mw.domain.syntax._
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A:Orderable](ls: List[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
}
trait Orderable[A] {
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
object Orderable {
implicit val intOrderable: Orderable[Int] = (l: Int, r: Int) => l - r
implicit val stringOrderable: Orderable[String] = (l: String, r: String) => l.compareTo(r)
def reverse[A](implicit order: Orderable[A]): Orderable[A] = new Orderable[A] {
override def compare(l: A, r: A): Int = order.compare(r, l)
}
def by[A, B](f: A => B)(implicit order: Orderable[B]): Orderable[A] = new Orderable[A] {
override def compare(l: A, r: A): Int = order.compare(f(l), f(r))
}
}
final case class Person(age: Int, name: String)
object Person {
implicit val personOrder: Orderable[Person] =
Orderable.by (person => person.age)
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
package object syntax {
implicit class OrderableSyntax[A](a: A)(implicit order: Orderable[A]) {
def <(other: A): Boolean = order.<(a, other)
}
}
41. Monty West
Ok, so we have managed to get this to look, if I just undo that, a lot like what we
had before, with this nice syntax that we are all familiar with and happy with, this is
pretty readable.
def sort[A: Orderable](ls: List[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
All we had to add was this context bound. For the person itself, that we want to
sort, we had to add this couple of lines, separate to the class:
final case class Person(age: Int, name: String)
object Person {
implicit val personOrderable: Orderable[Person] = new Orderable[Person] {
/** *
* l < r : negative
* l = r : zero
* l > r : positive
*/
override def compare(l: Person, r: Person): Int = l.age - r.age
}
}
we didn’t have to change the class at all.
42. But what we did have to do a lot of was a lot of this stuff, like there is quite a lot of
code gone into this type class
trait Orderable[A] {
/***
* l < r : negative
* l = r : zero
* l > r : positive
*/
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
object Orderable {
implicit val intOrderable: Orderable[Int] = (l: Int, r: Int) => l - r
implicit val stringOrderable: Orderable[String] =
(l: String, r: String) =>
if (l == r) 0
else if (l < r) -1
else 1
def by[A, B](f: A => B)(implicit order: Orderable[B]): Orderable[A] =
(l: A, r: A) => order.compare(f(l), f(r))
def reverse[A](implicit order: Orderable[A]): Orderable[A] =
(l: A, r: A) => order.compare(r, l)
}
Monty West
43. Monty West
In our actual application code nothing much has changed. We haven’t change our class
and we haven’t changed our sort too much. So it would be great if we could get rid of
all this boilerplate, if we didn’t have to define this ourselves, so we just delete it.
trait Orderable[A] {
/***
* l < r : negative
* l = r : zero
* l > r : positive
*/
def compare(l: A, r: A): Int
def <(l: A, r: A): Boolean = compare(l, r) < 0
}
object Orderable {
implicit val intOrderable: Orderable[Int] = (l: Int, r: Int) => l - r
implicit val stringOrderable: Orderable[String] =
(l: String, r: String) =>
if (l == r) 0
else if (l < r) -1
else 1
def by[A, B](f: A => B)(implicit order: Orderable[B]): Orderable[A] =
(l: A, r: A) => order.compare(f(l), f(r))
def reverse[A](implicit order: Orderable[A]): Orderable[A] =
(l: A, r: A) => order.compare(r, l)
}
44. And we delete syntax
package object syntax {
implicit class OrderableSyntax[A](a: A)(implicit order:Orderable[A]) {
def <(other: A): Boolean = order.<(a, other)
}
}
Monty West
Obviously these imports are not going to work now
45. @philip_schwarz
What Monty West has been doing all along, since he ditched subtype
polymorphism and switched to ad hoc polymorphism using type classes, is apply
ideas and techniques that are heavily exploited in the Cats library. That’s why his
talk contains the following slides:
46. Monty West
So what if we still want to sort persons? What can we do if we want to use type
classes and stuff?
That’s where Cats comes in. So Cats’ version of Orderable is called Order, so if I
import cats.Order and in the context bound I replace Orderable with Order, and
now I don’t have this nice syntax,
47. import cats.Order
import cats.syntax.order._
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A: Order](ls: List[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs =>
sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
}
Monty West
But, again, Cats provides, so if I import cats.syntax.order._, now that looks exactly the
same, and this is actually a tiny bit of code, I’ve got two imports and a context bound, I
mean, and we can do this sort of generic sorting
49. Monty West
but again Cats gives you a lot of instances for free
Now that compiles and what we have done here is very little work.
We have added a couple of imports, context bounds, added a person instance to implicit
scope, a couple of imports and we have done, and we have done a generic sort.
And we have done it all without having to change our Person class. Our Person class can
be somewhere completely separate. And we don’t have to change that.
We can do this for types we don’t own, obviously we don’t own the Order type class itself,
Cats owns that, so we can add this functionality anywhere.
50. @philip_schwarz
Recap - Version 3
Using Cats
import cats.Order
import cats.syntax.order._
package object ops {
def sortInts(ls: List[Int]): List[Int] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sortInts(xs.filter(a => a < x)) ++ List(x) ++ sortInts(xs.filterNot(a => a < x))
}
def sort[A:Order](ls: List[A]): List[A] = ls match {
case Nil => Nil
case _ :: Nil => ls
case x :: xs => sort(xs.filter(a => a < x)) ++ List(x) ++ sort(xs.filterNot(a => a < x))
}
}
import cats.Order
import cats.instances.int._
final case class Person(age: Int, name: String)
object Person {
implicit val personOrder: Order[Person] =
Order.by(_.age)
}
val personLs =
List(
Person(23, "alice"),
Person(35, "bob"),
Person(21, "charlie")
);
val intLs =
List(-5, 8, 10, 2, 5);
51. Monty West
https://www.linkedin.com/in/monty-west/
I just want to quickly show, or explain what this has actually done for us. So what we can do is, we have
added functionality to the Person object, without changing it at all, so we are now able to compare
Persons.
Obviously this is quite a powerful approach and we could go on like this forever, we could add loads of
functionality to our classes without ever needing to change them, without them ever needing to be
anything other than value classes or just simple data classes, and more than that, just a quick taste of the
sort of power you can get to, without any actual work, say we wanted to incorporate the name into the
sort, so if we import instances for string and tuple, what we can do is we can get this to return a tuple
So what this will do is it will
sort by age and if they are
the same it will sort by
name.
Again, very minimal code for
what is quite a lot of
functionality that we didn’t
have to define ourselves.
Again, we have added three
lines of code.
52. Monty West
And another nice thing about Cats which I don’t think a lot of people really enjoy, is that if you can’t
remember where all these instances and syntax are, there is just this magic import you can do,
cats.implicits._, just makes everything compile.
And that’s basically the talk. I have ended up with five extra lines of code from where I started, so, a
very slow live code session, but unlocked quite a lot of functionality.
Question from the audience: “do you find that using the cats.implicits._ instead of the dedicated
imports affects the compiler?”
Answer: Yes, so adding this cats.implicits._ is expensive for you compiler, you will find the compiler will
go slower, it is good to remember where all these things are, but if you are really struggling,
cats.implicits._ can help, and especially when you get quite deep into all this stuff. Occasionally you’ll
find no hit and it just makes everything work, makes everything clean.
54. Monty West
https://www.linkedin.com/in/monty-west/
OK, so that’s the end of the live coding portion.
Let’s just go back and summarise where we got to.
So over subtype polymorphism, this sort of ad hoc polymorphism with type classes, we can add
functionality to types we don’t own, which can be very useful, we can change that functionality in different
scopes, so if we want to have a different sort function, a different way of doing toString is a similar one, then
we can do that in different scopes, again, a higher level of abstraction where we are able to compose these
instances, creating instances on the fly very easily, it makes them more applicable as well.
And I think the good thing here is it enables things like Cats. The Cats library just adds functionality to types
it doesn’t own, Order, that’s exactly what it does. That is not possible with subtype polymorphism
obviously. You’d have to go through and implement everything and what if you wanted to do this for Java
Time instant for example? The Cats library would be useless.
So this pattern enables stuff like Cats, which I think a lot of people find very useful. And yes, as we all like, it
does your work for you.