2010-04-05 19 views
7

J'essaie de saisir le polymorphisme d'ordre supérieur dans scala en implémentant une interface très basique qui décrit une monade mais je rencontre un problème que je ne comprends pas vraiment.Pratique courante pour le polymorphisme d'ordre supérieur dans scala

I mis en œuvre la même chose avec C++ et le code ressemble à ceci:

#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; 
} 

Lorsque vous essayez de faire la même chose avec scala I Fail:

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) 
    } 
} 

Le compilateur se plaint:

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

Qu'est-ce que je fais mal ici? Il semble y avoir un concept fondamental que je ne semble pas comprendre à propos des typographes scala.

Cordialement, raichoo

+0

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

+0

Merci, ce lien semble très intéressant, mais ne répond pas vraiment à ma question. Je ne voulais pas savoir quoi que ce soit au sujet monades, ma question était sur le polymorphisme constructeur de type. Même si, il ressemble à une bonne lecture. :) – raichoo

Répondre

16

Le trait Monad à Scala serait déclarée comme suit:

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

Notez qu'il est paramétré avec un constructeur de type M[_]. Le trait de soulignement entre parenthèses indique que M est un constructeur de type de type(* -> *) (c'est-à-dire M prend un certain type A pour construire un type M[A]). Votre instance identité monade serait alors écrit comme ceci:

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) 
} 

Cette définition utilise des paramètres par nom pour atteindre la sémantique paresseux.

La classe Scalaz contient des classes de type monad ainsi que d'autres classes utiles de types plus élevés, ainsi que de nombreuses instances pour les bibliothèques Java/Scala standard.

+0

incroyable, ma tête a explosé, mais c'était ce que je cherchais. Merci :) – raichoo

3

Je ne sais pas quelle serait la meilleure solution, mais dans la définition de pur dans votre code:

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

Qu'est-ce Container[A](a) devrait faire? Jusqu'à présent, vous avez défini Container comme un type générique XXX et vous n'avez aucune information sur la façon de construire un nouvel objet. Vous devez passer un objet "constructeur" en tant que paramètre implicite. Jetez un oeil à la façon dont les bibliothèques de collecte sont mis en œuvre Scala 2.8 ou la définition Monad dans Scalaz

5

Si vous changez votre définition de la Monad classe à ce qui suit

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

La syntaxe Container[_] est de savoir comment les types plus sont exprimés en Scala. Le A <% Container[A] est une 'vue liée' qui exprime que A est implicitement convertible en Container[A]. Le corps de la méthode utilise cette conversion implicite. Pour utiliser cette classe, vous devez avoir une conversion implicite dans la portée de (dans votre exemple) Int à Value[Int]

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

Vous pouvez alors effectuer les opérations suivantes

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

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

Désolé Container [_] n'est pas un type plus kinded à Scala comme je viens d'apprendre dans [what-is-a-plus-kinded-type en scala] (http://stackoverflow.com/questions/6246719/what-is-a-plus-kinded-type en scala) – Lutz