2010-04-05 41 views
7

我試圖通過實現描述monad的非常基本的界面來理解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; 
} 

當試圖做同樣的使用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) 
    } 
} 

編譯器抱怨:

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

我在這裏做錯了什麼?似乎有一個基本的概念,我似乎並不瞭解scala typeconstructor。

問候, raichoo

+0

http://stackoverflow.com/questions/1992532/monad-trait-in-scala – missingfaktor 2010-04-05 13:30:56

+0

謝謝,那個鏈接看起來很有趣,但並沒有真正回答我的問題。我不想知道單子的任何事情,我的問題是關於類型構造函數多態性。儘管如此,它看起來很不錯。 :) – raichoo 2010-04-05 14:04:07

回答

16

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來構造類型M[A])。然後,您的身份monad實例將如下所示:

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

此定義使用by-name參數實現惰性語義。

單元和其他有用的高級類型類由Scalaz庫提供,以及標準Java/Scala庫的很多實例。

+0

令人驚異的是,我的腦袋剛剛爆炸,但那正是我一直在尋找的東西。謝謝 :) – raichoo 2010-04-05 16:45:02

3

不知道什麼是最好的解決辦法,但在純粹的定義代碼:

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

什麼Container[A](a)應該怎麼辦?到目前爲止,您已經將Container定義爲泛型類型XXX,並且您沒有關於如何構建新對象的任何信息。您需要將「構建器」對象作爲隱式參數傳遞。 看看收集庫是如何在斯卡拉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]。該方法的主體使用這種隱式轉換。要使用這個類,你需要有餘地的隱式轉換(在你的例子)IntValue[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

對不起容器[_]是不是在斯卡拉更高的kinded類型,就像我剛剛在[什麼是更高的kinded-type-in​​-scala]中學到的(http://stackoverflow.com/questions/6246719/what-is-higher-kinded-type-in​​-scala) – Lutz 2011-06-28 13:53:40