Обычная практика для полиморфизма высшего порядка в scala

Я пытаюсь схватить higher-order-polymophism в 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;
}

При попытке сделать то же с scala я перестал работать:

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

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

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

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

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

7
задан Apocalisp 5 April 2010 в 21:32
поделиться

3 ответа

Типаж 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)
}

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

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

16
ответ дан 6 December 2019 в 07:25
поделиться

Если вы измените определение класса 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] = Monad@781fb069

scala> m.pure(1).value         
res3: Int = 1
5
ответ дан 6 December 2019 в 07:25
поделиться

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

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

Что должен делать Контейнер [A] (a) ? До сих пор вы определили контейнер как универсальный тип XXX, и у вас нет информации о том, как создать новый объект. Вам необходимо передать объект "строитель" как неявный параметр. Посмотрите, как библиотеки коллекций реализованы в Scala 2.8 или определение Monad в Scalaz

3
ответ дан 6 December 2019 в 07:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: