En aquest tema, explorarem dos conceptes fonamentals en la programació funcional: els Functors i les Monads. Aquests conceptes són essencials per treballar amb estructures de dades i efectes de manera funcional i composable.
Introducció
Què és un Functor?
Un Functor és una estructura que pot ser mappejada. En altres paraules, és una estructura que implementa una operació map que aplica una funció a cada element dins de la seva estructura.
Què és una Monad?
Una Monad és una estructura que representa càlculs seqüencials. Les Monads proporcionen una manera de seqüenciar operacions, encapsulant valors i efectes de manera que es puguin composar fàcilment.
Functors
Definició de Functor
Un Functor és qualsevol tipus que implementa la interfície map. En Scala, això es pot representar amb la següent signatura:
Exemple de Functor: Option
L'objecte Option és un exemple clàssic de Functor. Vegem com funciona:
val someValue: Option[Int] = Some(10) val noneValue: Option[Int] = None val incrementedSome: Option[Int] = someValue.map(_ + 1) // Some(11) val incrementedNone: Option[Int] = noneValue.map(_ + 1) // None
Exercici Pràctic: Implementar un Functor
Implementa un Functor per a una llista personalitzada:
sealed trait MyList[+A]
case object MyNil extends MyList[Nothing]
case class MyCons[+A](head: A, tail: MyList[A]) extends MyList[A]
object MyList {
def map[A, B](list: MyList[A])(f: A => B): MyList[B] = list match {
case MyNil => MyNil
case MyCons(head, tail) => MyCons(f(head), map(tail)(f))
}
}Monads
Definició de Monad
Una Monad és qualsevol tipus que implementa les operacions flatMap i unit (també coneguda com pure o return). En Scala, això es pot representar amb la següent signatura:
Exemple de Monad: Option
L'objecte Option també és un exemple de Monad. Vegem com funciona:
val someValue: Option[Int] = Some(10) val noneValue: Option[Int] = None val resultSome: Option[Int] = someValue.flatMap(x => Some(x + 1)) // Some(11) val resultNone: Option[Int] = noneValue.flatMap(x => Some(x + 1)) // None
Exercici Pràctic: Implementar una Monad
Implementa una Monad per a una llista personalitzada:
sealed trait MyList[+A]
case object MyNil extends MyList[Nothing]
case class MyCons[+A](head: A, tail: MyList[A]) extends MyList[A]
object MyList {
def flatMap[A, B](list: MyList[A])(f: A => MyList[B]): MyList[B] = list match {
case MyNil => MyNil
case MyCons(head, tail) => concat(f(head), flatMap(tail)(f))
}
def unit[A](a: A): MyList[A] = MyCons(a, MyNil)
def concat[A](list1: MyList[A], list2: MyList[A]): MyList[A] = list1 match {
case MyNil => list2
case MyCons(head, tail) => MyCons(head, concat(tail, list2))
}
}Comparació entre Functors i Monads
| Característica | Functor | Monad |
|---|---|---|
| Operació clau | map |
flatMap i unit |
| Propòsit | Transformar elements dins d'una estructura | Seqüenciar operacions i encapsular efectes |
Exercicis Pràctics
-
Implementar un Functor per a
Either:sealed trait MyEither[+E, +A] case class MyLeft[+E](value: E) extends MyEither[E, Nothing] case class MyRight[+A](value: A) extends MyEither[Nothing, A] object MyEither { def map[E, A, B](either: MyEither[E, A])(f: A => B): MyEither[E, B] = either match { case MyLeft(e) => MyLeft(e) case MyRight(a) => MyRight(f(a)) } } -
Implementar una Monad per a
Either:object MyEither { def flatMap[E, A, B](either: MyEither[E, A])(f: A => MyEither[E, B]): MyEither[E, B] = either match { case MyLeft(e) => MyLeft(e) case MyRight(a) => f(a) } def unit[E, A](a: A): MyEither[E, A] = MyRight(a) }
Resum
En aquest tema, hem après sobre dos conceptes fonamentals en la programació funcional: els Functors i les Monads. Hem vist com aquests conceptes ens permeten treballar amb estructures de dades i efectes de manera composable i funcional. Hem explorat exemples pràctics amb Option i hem implementat Functors i Monads per a estructures personalitzades.
En el proper tema, explorarem les For-Comprehensions, una característica poderosa de Scala que facilita el treball amb Monads.
Curs de Programació en Scala
Mòdul 1: Introducció a Scala
- Introducció a Scala
- Configuració de l'Entorn de Desenvolupament
- Conceptes Bàsics de Scala: Sintaxi i Estructura
- Variables i Tipus de Dades
- Operacions Bàsiques i Expressions
Mòdul 2: Estructures de Control i Funcions
- Declaracions Condicionals
- Bucles i Iteracions
- Funcions i Mètodes
- Funcions d'Ordre Superior
- Funcions Anònimes
Mòdul 3: Col·leccions i Estructures de Dades
- Introducció a les Col·leccions
- Llistes i Arrays
- Conjunts i Mapes
- Tuples i Options
- Coincidència de Patrons
Mòdul 4: Programació Orientada a Objectes en Scala
- Classes i Objectes
- Herència i Traits
- Classes Abstractes i Classes Case
- Objectes Companys
- Objectes Singleton
Mòdul 5: Programació Funcional en Scala
- Immutabilitat i Funcions Pures
- Estructures de Dades Funcionals
- Monads i Functors
- For-Comprehensions
- Gestió d'Errors en la Programació Funcional
Mòdul 6: Conceptes Avançats de Scala
- Conversions i Paràmetres Implícits
- Classes de Tipus i Polimorfisme
- Macros i Reflexió
- Concurrència en Scala
- Introducció a Akka
