我试图通过实现描述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
答案 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]
。方法的主体使用此隐式转换。要使用此类,您需要在(在您的示例中)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
答案 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定义