7

我试图通过实现一个描述 monad 的非常基本的接口来掌握 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 类型构造函数的基本概念我似乎不了解。

问候, raichoo

4

3 回答 3

16

Scala 中的Monadtrait 将声明如下:

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库提供了 Monad 和其他有用的高级类型类以及标准 Java/Scala 库的大量实例。

于 2010-04-05T16:18:12.297 回答
5

如果您将Monad类的定义更改为以下

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

语法Container[_]是如何在 Scala 中表达更高的种类。TheA <% Container[A]是一个“视图绑定”,表示A可以隐式转换为Container[A]. 该方法的主体使用这种隐式转换。要使用此类,您需要在范围内进行隐式转换(在您的示例中)IntValue[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
于 2010-04-05T14:53:00.450 回答
3

不知道什么是最好的解决方案,但在你的代码中对 pure 的定义:

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

应该怎么Container[A](a)做?到目前为止,您已经将 Container 定义为泛型类型 XXX,并且您没有任何关于如何构建新对象的信息。您需要将“builder”对象作为隐式参数传递。看看集合库是如何在 Scala 2.8 或 Scalaz 中的 Monad 定义实现的

于 2010-04-05T14:44:53.110 回答