2010-04-05 26 views
7

Estoy tratando de captar el polimorfismo de orden superior en Scala implementando una interfaz muy básica que describe una mónada pero me encuentro con un problema que realmente no entiendo.Práctica común para el polimorfismo de orden superior en scala

que implementan la misma con C++ y el código es el siguiente:

#include <iostream> 

template <typename T> 
class Value { 
private: 
    T value; 
public: 
    Value(const T& t) { 
    this->value = t; 
    } 

    T get() { 
    return this->value; 
    } 
}; 

template < template <typename> class Container > 
class Monad { 
public: 
    template <typename A> Container<A> pure(const A& a); 
}; 

template <template <typename> class Container> 
    template <typename A> 
Container<A> Monad<Container>::pure(const A& a) { 
    return Container<A>(a); 
} 

int main() { 
    Monad<Value> m; 
    std::cout << m.pure(1).get() << std::endl; 
    return 0; 
} 

Al tratar de hacer lo mismo con Scala fallo:

class Value[T](val value: T) 

class Monad[Container[T]] { 
    def pure[A](a: A): Container[A] = 
    Container[A](a) 
} 

object Main { 
    def main(args: Array[String]): Unit = { 
    val m = new Monad[Value] 
    m.pure(1) 
    } 
} 

El compilador se queja de:

[[email protected]:Scala]:434> scalac highorder.scala 
highorder.scala:5: error: not found: value Container 
    Container[A](a) 
    ^
one error found 

¿Qué estoy haciendo mal aquí? Parece que hay un concepto fundamental que no parece entender sobre los constructores tipo scala.

Saludos, raichoo

+0

http://stackoverflow.com/questions/1992532/monad-trait-in-scala – missingfaktor

+0

Gracias, ese enlace parece muy interesante pero realmente no responde mi pregunta. No quería saber nada sobre las mónadas, mi pregunta era sobre el polimorfismo constructor de tipos. A pesar de que parece una buena lectura. :) – raichoo

Respuesta

16

El rasgo Monad en Scala sería declarado de la siguiente manera:

trait Monad[M[_]] { 
    def pure[A](a: => A): M[A] 
    def bind[A,B](a: M[A], f: A => M[B]): M[B] 
} 

Tenga en cuenta que se ha parametrizado con un constructor de tipos M[_]. El guión bajo entre corchetes indica que M es un constructor de tipo de tipo(* -> *) (es decir, M toma algún tipo A para construir un tipo M[A]). La instancia mónada identidad sería entonces escribirse así:

class Value[A](a: => A) { lazy val value = a } 

implicit val identityMonad = new Monad[Value] { 
    def pure[A](a: => A) = new Value(a) 
    def bind[A,B](a: Value[A], f: A => Value[B]) = new Value(f(a.value).value) 
} 

Esta definición utiliza parámetros por nombre de lograr la semántica perezosos.

La biblioteca Scalaz proporciona clases de mónadas y otros tipos útiles de alto grado junto con muchas instancias para las bibliotecas estándar de Java/Scala.

+0

Increíble, mi cabeza explotó, pero eso era lo que estaba buscando. Gracias :) – raichoo

3
No

seguro de lo que sería la mejor solución, pero en la definición de puros en su código:

class Monad[Container[T]] { 
    def pure[A](a: A): Container[A] = Container[A](a) 
} 

Lo Container[A](a) debe hacer? Hasta ahora, ha definido Container como un tipo genérico XXX y no tiene información sobre cómo crear un nuevo objeto. Debe pasar un objeto "generador" como parámetro implícito. Tome un vistazo a cómo las bibliotecas de recogida se implementan en Scala 2.8 o la definición Mónada en Scalaz

5

Si cambia de definición de la clase Monad a la siguiente

class Monad[Container[_]] {   
    def pure[A <% Container[A]](a: A): Container[A] = a 
} 

La sintaxis Container[_] es como tipos más altos se expresan en Scala. El A <% Container[A] es un 'view bound' que expresa que A es implícitamente convertible a Container[A]. El cuerpo del método usa esta conversión implícita. Para utilizar esta clase, es necesario tener una conversión implícita en su alcance por (en el ejemplo) Int a Value[Int]

implicit def toValue[T](t:T) = new Value(t) 

A continuación, puede hacer lo siguiente

scala> val m = new Monad[Value]      
m: Monad[Value] = [email protected] 

scala> m.pure(1).value   
res3: Int = 1 
+0

Sorry Container [_] no es un tipo de kinded superior en Scala como acabo de aprender en [what-is-a-higher-kinded-type-in-scala] (http://stackoverflow.com/questions/6246719/what-is-a-higher-kinded-type-in-scala) – Lutz

Cuestiones relacionadas