2017-07-23 126 views
0

我正在Scalaz中深入探索Monoid的實現。如果您在Monoid上定義附加操作,我碰到|+|運營商應該來開箱即用。該算子的定義在SemigroupSyntax。該班通過Semigroup獲得Monoid。Scalaz實現使用先進的Scala功能的Semigroup

檢查這三個類之後,我有一個重要的問題 - 究竟是如何從SemigroupSyntax實現/** Wraps a value `self` and provides methods related to `Semigroup` */

有一些魔術implicits,在SemigroupSyntax呼籲.this對性狀多的評論,我老實說不明白。

如果有人能花時間開導我,我會愛上。

預先感謝您!

編輯:

我渴望瞭解這個類的工作方式:

package scalaz 
package syntax 

/** Wraps a value `self` and provides methods related to `Semigroup` */ 
final class SemigroupOps[F] private[syntax](val self: F)(implicit val F: Semigroup[F]) extends Ops[F] { 
    //// 
    final def |+|(other: => F): F = F.append(self, other) 
    final def mappend(other: => F): F = F.append(self, other) 
    final def ⊹(other: => F): F = F.append(self, other) 
    //// 
} 

trait ToSemigroupOps { 
    implicit def ToSemigroupOps[F](v: F)(implicit F0: Semigroup[F]) = 
    new SemigroupOps[F](v) 

    //// 
    //// 
} 

trait SemigroupSyntax[F] { 
    implicit def ToSemigroupOps(v: F): SemigroupOps[F] = new SemigroupOps[F](v)(SemigroupSyntax.this.F) 

    def F: Semigroup[F] 
    //// 
    def mappend(f1: F, f2: => F)(implicit F: Semigroup[F]): F = F.append(f1, f2) 

    //// 
} 

而且其調用點半羣:

val semigroupSyntax = new scalaz.syntax.SemigroupSyntax[F] { def F = Semigroup.this } 
+1

如果你粘貼你不明白的代碼會更容易幫助你。 – pedrofurla

回答

0

最容易迷失方向這裏的事情是,有實際上是兩條路線獲取對象的操作。

默認的第一條路線是import scalaz.syntax.semigroup._。它爲所有隱式可用的實例添加運算符。

  1. 任何Semigroup實例爲自己創建的SemigroupSyntax的實施,確定在this方面的F方法。
  2. 在scalaz/syntax/package.scala中,有一個syntax單身對象,它可以擴展Syntaxes特質。這是導入定義的第一部分。
  3. 在scalaz/syntax/Syntax.scala中,Syntaxes特性中有一個semigroup單身物件,用於syntax中,它擴展了ToSemigroupOps。我們正在導入此對象的內容,僅包含隱式轉換。轉換的目的是捕獲隱式提供的Semigroup實例並構造包含所有操作的包裝器SemigroupOps

第二條路線是import [your_semigroup_instance].semigroupSyntax._的快捷方式,Semigroup是您列出的呼叫站點。它將運算符添加到特定類型,其中實例爲。

  1. semigroupSyntax是匿名的實現SemigroupSyntax性狀,其中F方法被定義爲的Semigroup一個特定實例的。
  2. SemigroupSyntax特徵本身,如ToSemigroupOps,提供隱式轉換爲SemigroupOps,但它不使用捕獲隱式提供的實例,而是使用其F方法。所以我們得到類型爲F的運營商,使用特定的Semigroup類型類實現。
+0

謝謝你的詳細解釋。即使我多次閱讀,但我還是不太瞭解,但我有一些簡單的問題。 圖書館設計師如何從所有這些誤導中獲益?它關於代碼的可擴展性嗎?因爲在我看來,這件事情是要保持的。 – zaxme

+1

設計實際上是非常模塊化的:每個類型類型有一個文件,另一個用於語法,並且在Syntax.scala中有單行註冊(另外,可能還有一些'scalaz.std'中的實例)。類型類的代碼及其語法包裝遵循通用模式,並且,雖然沒有在Scalaz中使用,但代碼生成編譯器插件(https://github.com/mpilquist/simulacrum)。儘管包裝機制本身的設計與Haskell編碼實踐非常相似,但看起來很複雜,但庫架構仍然清晰且鬆散耦合。 –