monadas - ¿Qué es exactamente lo que hace que Option sea una mónada en Scala?
monadas filosofia (3)
Cualquier cosa que implemente (parcialmente), a través de pato-tipado, el rasgo FilterMonadic
se considera una mónada en Scala. Esto es diferente a cómo se representan las mónadas en Haskell, o la clase de Monad
en scalaz . Sin embargo, para beneficiarse del azúcar sintáctico de comprensión en Scala, un objeto debe exponer algunos de los métodos definidos en el rasgo FilterMonadic
.
Además, en Scala, el equivalente de la función de return
Haskell es la palabra clave yield
utilizada para producir valores de a for
comprensión. El deslumbramiento del yield
es una llamada al método del map
de la "mónada".
Sé lo que son las mónadas y cómo usarlas. Lo que no entiendo es lo que hace, digamos, ¿ Option
una mónada?
En Haskell una mónada Maybe
es una mónada porque está instanciada a partir de la clase Monad
(que tiene al menos 2 funciones necesarias para return
y bind
que hace que la clase Monad
, de hecho, una mónada).
Pero en Scala tenemos esto:
sealed abstract class Option[+A] extends Product with Serializable { ... }
trait Product extends Any with Equals { ... }
Nada relacionado con una mónada.
Si creo mi propia clase en Scala, ¿será una mónada por defecto? Por qué no?
La forma en que lo expongo es que hay una distinción emergente entre las mónadas como un patrón de diseño frente a una abstracción de primera clase . Haskell tiene el último, en la forma de la clase de tipo Monad
. Pero si tienes un tipo que tiene (o puede implementar) las operaciones monádicas y obedece las leyes, eso también es una mónada.
Estos días puedes ver las mónadas como un patrón de diseño en las bibliotecas de Java 8. Los tipos Optional
y Stream
en Java 8 vienen con un método estático que corresponde al return
Haskell y un método flatMap
. Sin embargo, no hay tipo de Monad
.
En algún punto intermedio también tienes el enfoque de "pato-tipado", como lo llama la respuesta de Ionuţ G. Stan. C # tiene esto también: la sintaxis de LINQ no está vinculada a un tipo específico, sino que se puede usar con cualquier clase que implemente ciertos métodos.
Monad
es un concepto, una interfaz abstracta si se quiere, que simplemente define una forma de componer datos.
Option
admite la composición a través de flatMap
, y eso es prácticamente todo lo que se necesita para usar la "insignia de mónada".
Desde un punto de vista teórico, también debería:
- admite una operación de
unit
(return
, en términos de Haskell) para crear una mónada a partir de un valor baremo, que en el caso deOption
es el constructorSome
- respetar las leyes monádicas
pero esto no está estrictamente impuesto por Scala.
Las mónadas en scala son un concepto mucho más flexible que en Haskell, y el enfoque es más práctico. Las únicas mónadas son relevantes para, desde la perspectiva del lenguaje, la capacidad de ser utilizado en una comprensión forzosa.
flatMap
es un requisito básico, y opcionalmente puede proporcionar un map
, withFilter
y foreach
.
Sin embargo, no existe la conformidad estricta con una clase de Monad
, como en Haskell.
Aquí hay un ejemplo: definamos nuestra propia mónada.
class MyMonad[A](value: A) {
def map[B](f: A => B) = new MyMonad(f(value))
def flatMap[B](f: A => MyMonad[B]) = f(value)
override def toString = value.toString
}
Como ve, solo estamos implementando map
y flatMap
(bueno, y toString
como un producto). Felicitaciones, tenemos una mónada! Probémoslo:
scala> for {
a <- new MyMonad(2)
b <- new MyMonad(3)
} yield a + b
// res1: MyMonad[Int] = 5
¡Bonito! No estamos realizando ningún tipo de filtrado, por lo que no es necesario implementarlo con withFilter
. Además, dado que estamos generando un valor, tampoco necesitamos foreach
. Básicamente, implementas todo lo que desees, sin requisitos estrictos. Si intentas filtrar en una comprensión withFilter
y no has implementado con withFilter
, simplemente obtendrás un error de tiempo de compilación.