19 ans d’expérience professionnelle
dans le développement
ESN 😮
Plus récemment dans un organisme de paiement
Actuellement chez un éditeur SaaS
dans la data
Principalement autour des langages JVM
Mais rentrons dans le vif du sujet
FP…
E → F
x ↦ f(x)
Il s’agit d’une transformation
d’une valeur appartement à l’ensemble de départ
vers une valeur appartenant à l’ensemble d’arrivée.
def sayHello(niceMessage: String): Unit =
println(s"Hello $niceMessage")
sayHello("world!")
Hello world!
def dice(): Int =
Random.nextInt(6) + 1
dice()
val res0: Int = 5
dice()
val res1: Int = 3
def nowPlus(days: Long): Instant =
Instant.now().plus(days, ChronoUnit.DAYS)
nowPlus(3)
val res0: java.time.Instant = 2024-03-05T18:55:34.125784Z
nowPlus(5)
val res1: java.time.Instant = 2024-03-07T18:55:34.215660Z
def saveArticle(id: UUID, content: String, author: Author)(
database: Database
): Boolean =
database.executeQuery(
"""INSERT INTO Article(id, content, author_name, author_email)
|VALUES (:id, :content, :author_name, :author_email);
|""".stripMargin,
"id" -> id,
"content" -> content,
"author_name" -> author.name,
"author_email" -> author.email
)
saveArticle(
UUID.fromString("0d975fff-44dc-4110-b21a-1f31148969b8"),
"<p>Great content</p>",
Author("Sébastian", "seb@example.com")
)(postgresql)
val res0: Boolean = true
Toutes ces fonctions sont impures car :
Permet donc des optimisations massivement parallélisables
f ∘ g
f(g(x))
Il s’agit d’un moyen de garantir
case class User(name: String, age: Int)
enum Category:
case Young, Adult, Old
val categoryByMaxAges: Map[Int, Category] =
Map(
24 -> Category.Young,
64 -> Category.Adult,
Integer.MAX_VALUE -> Category.Old
)
val discountByCategories: Map[Category, Int] =
Map(
Category.Young -> 25,
Category.Adult -> 0,
Category.Old -> 35
)
def computePrice(
user: User,
categories: Map[Int, Category],
price: Long,
discounts: Map[Category, Int]
): Long = price - price * discounts(
categories
.filter { case (maxAge, category) => maxAge >= user.age }
.minBy { case (maxAge, category) => maxAge }
._2
) / 100
computePrice( computePrice( computePrice(
User("Emma", 16), User("Nicolas", 41), User("Martine", 67),
categoryByMaxAges, categoryByMaxAges, categoryByMaxAges,
price = 1999, price = 5500, price = 4999,
discountByCategories discountByCategories discountByCategories
) ) )
val res0: Long = 1500 val res1: Long = 5500 val res2: Long = 3250
def computePrice(
user: User,
categories: Map[Int, Category],
price: Long,
discounts: Map[Category, Int]
): Long =
computePrice(
price,
computeDiscount(user, categories, discounts)
)
def computePrice(price: Long, discount: Long): Long =
price - price * discount / 100
def computeDiscount(
user: User,
categories: Map[Int, Category],
discounts: Map[Category, Int]
): Long = discounts(findCategory(user, categories))
def findCategory(
user: User,
categories: Map[Int, Category]
): Category =
val (_, category) = categories
.filter { case (maxAge, category) => maxAge >= user.age }
.minBy { case (maxAge, category) => maxAge }
category
Une fonction est considérée comme un type de données comme les autres.
def logBeforeAndAfter(message: String, task: () => Unit): Unit =
println(s"before $message")
task()
println(s" after $message")
logBeforeAndAfter("hello", () => { println("Hello World!") })
before hello
Hello World!
after hello
def logBeforeAndAfterResult(
message: String,
computeResult: String => Long
): Unit =
println(s"before $message")
println(s"result ${computeResult(message)}")
println(s" after $message")
logBeforeAndAfterResult("hello", message => message.length)
before hello
result 5
after hello
Une fonction est considérée comme un type de données comme les autres.
def operationToCompute(operation: String): (Long, Long) => Long =
operation match
case "add" => (left, right) => left + right
case "subtract" => (left, right) => left - right
case "multiply" => (left, right) => left * right
case _ => (left, right) => Long.MinValue
operationToCompute("add")(3, 2)
val res0: Long = 5
operationToCompute("subtract")(3, 2)
val res1: Long = 1
operationToCompute("multiply")(3, 2)
val res2: Long = 6
operationToCompute("divide" )(3, 2)
val res3: Long = -9223372036854775808
La possibilité pour une fonction de se rappeler elle-même. Permet de traiter :
L’appel récursif est la dernière évaluation dans l’implémentation de la fonction
Permet d’éviter des épuisements de la pile d’exécution (aka StackOverflow®)
val input = """34
|84
|12
|
|32
|28
|9
|7""".stripMargin
@tailrec
def sums(
input: List[String],
acc: Seq[Long] = Vector.empty,
sum: Long = 0
): Seq[Long] =
input match
case Nil => acc :+ sum
case "" :: tail => sums(tail, acc :+ sum)
case n :: tail => sums(tail, acc, sum + n.toLong)
sums(input.linesIterator.toList)
val res0: Seq[Long] = Vector(130, 76)
Press ESC to enter the slide overview.
Hold down the alt key (ctrl in Linux) and click on any element to zoom towards it using zoom.js. Click again to zoom back out.
(NOTE: Use ctrl + click in Linux.)
Automatically animate matching elements across slides with Auto-Animate.
Presentations look great on touch devices, like mobile phones and tablets. Simply swipe through your slides.
Add the r-fit-text
class to auto-size text
Hit the next arrow...
... to step through ...
... a fragmented slide.
There's different types of fragments, like:
grow
shrink
fade-out
fade-right, up, down, left
fade-in-then-out
fade-in-then-semi-out
Highlight red blue green
You can select from different transitions, like:
None -
Fade -
Slide -
Convex -
Concave -
Zoom
reveal.js comes with a few themes built in:
Black (default) -
White -
League -
Sky -
Beige -
Simple
Serif -
Blood -
Night -
Moon -
Solarized
Set data-background="#dddddd"
on a slide to change the background color. All CSS color formats are supported.
<section data-background-gradient=
"linear-gradient(to bottom, #ddd, #191919)">
<section data-background="image.png">
<section data-background="image.png" data-background-repeat="repeat" data-background-size="100px">
<section data-background-video="video.mp4,video.webm">
Different background transitions are available via the backgroundTransition option. This one's called "zoom".
Reveal.configure({ backgroundTransition: 'zoom' })
You can override background transitions per-slide.
<section data-background-transition="zoom">
Since reveal.js runs on the web, you can easily embed other web content. Try interacting with the page in the background.
Item | Value | Quantity |
---|---|---|
Apples | $1 | 7 |
Lemonade | $2 | 18 |
Bread | $3 | 2 |
These guys come in two forms, inline: The nice thing about standards is that there are so many to choose from
and block:
“For years there has been a theory that millions of monkeys typing at random on millions of typewriters would reproduce the entire works of Shakespeare. The Internet has proven this theory to be untrue.”
You can link between slides internally, like this.
There's a speaker view. It includes a timer, preview of the upcoming slide as well as your speaker notes.
Press the S key to try it out.
Presentations can be exported to PDF, here's an example:
Set data-state="something"
on a slide and "something"
will be added as a class to the document element when the slide is open. This lets you
apply broader style changes, like switching the page background.
Additionally custom events can be triggered on a per slide basis by binding to the data-state
name.
Reveal.on( 'customevent', function() {
console.log( '"customevent" has fired' );
} );
Press B or . on your keyboard to pause the presentation. This is helpful when you're on stage and want to take distracting slides off the screen.