¿Qué hace exactamente a Option una mónada en Scala?
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 de la clase Monad
(que tiene al menos 2 funciones necesarias return
y bind
que hace de 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?
3 answers
Monad
es un concepto, una interfaz abstracta si se quiere, que simplemente define una forma de componer datos.
Option
soporta composición a través de flatMap
, y eso es casi todo lo que se necesita para usar la"insignia de la mónada".
Desde un punto de vista teórico, también debería:
- admite una operación
unit
(return
, en términos de Haskell) para crear una mónada a partir de un valor desnudo, que en el caso deOption
es el constructorSome
- respeta la monádica leyes
Pero esto no es estrictamente aplicado 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. La única cosa para la que las mónadas son relevantes, desde la perspectiva del lenguaje, es la capacidad de ser utilizadas en un para-comprensión.
flatMap
es un requisito básico, y usted puede opcionalmente proporcionar map
, withFilter
y foreach
.
Sin embargo, no hay tal cosa como la conformidad estricta a un Monad
tipo de clase, 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 ves, solo estamos implementando map
y flatMap
(bueno, y toString
como una mercancía).
¡Felicidades, tenemos una mónada! Vamos a probarlo:
scala> for {
a <- new MyMonad(2)
b <- new MyMonad(3)
} yield a + b
// res1: MyMonad[Int] = 5
Agradable! No estamos haciendo ningún filtrado, por lo que no necesitamos implementar withFilter
. También dado que estamos produciendo un valor, no necesitamos foreach
tampoco. Básicamente implementas todo lo que deseas apoyar, sin requisitos estrictos. Si intenta filtrar en un for-comprehension y no has implementado withFilter
, simplemente obtendrás un error en tiempo de compilación.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-18 18:25:27
Cualquier cosa que (parcialmente) implemente, a través deFilterMonadic
el rasgo se considera una mónada en Scala. Esto es diferente de cómo se representan las mónadas en Haskell, o el Monad
typeclass in scalaz . Sin embargo, para beneficiarse del azúcar sintáctico de comprensión for
en Scala, un objeto tiene que exponer algunos de los métodos definidos en el rasgo FilterMonadic
.
También, en Scala, el equivalente de la función Haskell return
es la palabra clave yield
utilizada para producir valores a partir de una comprensión for
. El desugaring de yield
es una llamada al método map
de la "mónada".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-18 11:35:19
La forma en que lo pondría es que hay una distinción emergente entre mónadas como un patrón de diseño vs.Una abstracción de primera clase. Haskell tiene esta última, 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.
En estos días se puede ver 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 of
que corresponde a Haskell return
, y un método flatMap
. Sin embargo, no existe un tipo Monad
.
En algún punto intermedio también tienes el enfoque "tipo pato", como dice la respuesta de Ionuț G. Stan. C# también tiene esto: 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-18 17:43:53