scala中高阶多态的常见实践

时间:2010-04-05 12:15:03

标签: scala types polymorphism monads higher-kinded-types

我试图通过实现描述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 typeconstructors。

此致 raichoo

3 个答案:

答案 0 :(得分:16)

Scala中的Monad特征将声明如下:

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来构造类型{{1} }})。您的身份monad实例将按如下方式编写:

M[A]

此定义使用by-name参数来实现惰性语义。

Monad和其他有用的高级类型类由Scalaz库提供,还有许多标准Java / Scala库的实例。

答案 1 :(得分:5)

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

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

语法Container[_]是在Scala中表达更高种类的方式。 A <% 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

答案 2 :(得分:3)

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

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

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