2010-04-05 9 views
7

Я пытаюсь понять более высокий порядок-полимофизм в scala, реализуя очень простой интерфейс, который описывает монаду, но я сталкиваюсь с проблемой, которую я действительно не понимаю.Обычная практика для более высокого порядка-полиморфизма в scala

Я реализовал то же самое с C++, и код выглядит следующим образом:

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

При попытке сделать то же самое с Скале я не:

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

Компилятор жалуется:

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

Что я здесь делаю неправильно? Кажется, есть фундаментальная концепция, которую я, похоже, не понимаю о дизайнерах scala typeconstructors.

С уважением, raichoo

+0

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

+0

Спасибо, эта ссылка выглядит очень интересной, но на самом деле не отвечает на мой вопрос. Я не хотел ничего знать о монадах, мой вопрос касался полиморфизма типового конструктора. Хотя, похоже, это хорошо читается. :) – raichoo

ответ

16

Monad черта в Scala будет объявлен следующим образом:

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

Обратите внимание, что это параметрироваться с конструктором типа M[_]. Подчеркнутое подчеркивание указывает, что M является конструктором типа вид(* -> *) (т. Е. M принимает тип A для построения типа M[A]). Ваш экземпляр идентичности монады затем будет записан следующим образом:

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

Это определение используется по имени параметров для достижения ленивых семантик.

Monad и другие полезные классы более высокого класса предоставляются библиотекой Scalaz наряду с множеством экземпляров для стандартных библиотек Java/Scala.

+0

Удивительно, моя голова просто взорвалась, но это было то, что я искал. Благодаря :) – raichoo

3

Не уверен, что будет лучшим решением, но в определении чисто в вашем коде:

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

Что Container[A](a) должен делать? Пока вы определили Container как общий тип XXX, и у вас нет никакой информации о том, как создать новый объект. Вам нужно передать объект «строитель» как неявный параметр. Взгляните на то, как библиотеки коллекций реализованы в Scala 2.8 или определении Монады в Scalaz

5

Если вы измените свое определение Monad класса к следующим

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

с синтаксисом Container[_] в том, как высшие виды выражены в Scala. A <% Container[A] является «границей вида», которая выражает, что A неявно конвертируется в Container[A]. Тело метода использует это неявное преобразование. Чтобы использовать этот класс, вам нужно иметь неявное преобразование в области видимости (в вашем примере) Int к Value[Int]

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

Затем вы можете сделать следующее

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

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

Извините, контейнер [_] не похож на более высокий тип в Scala, как я только что узнал в [what-is-a-high-kind-type-in-scala] (http://stackoverflow.com/questions/6246719/what-is-a-high-kind-type-in-scala) – Lutz