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