如何使用scalaz的`Tagged Type`来替换我的类型别名?

时间:2014-09-21 14:02:10

标签: scala scalaz type-systems

我想将对象定义为函数并将其依赖于其他函数:

type FetchPage = String => String
type FindImages = String => List[String]

object WillFetchPage extends FetchPage {
    def apply(url:String):String = /* get content of the url */
}

class WillFindImages(fetchPage: FetchPage) extends FindImages {
    def apply(url:String):List[String] = {
       val html = fetchPage(url)
       // get image srcs from the <img> tags
    }
}

然后我可以WillFetchPage注入WillFindImages

val findImages = new WillFindImages(WillFetchPage)

还可以通过注入模拟函数轻松地测试WillFindImages

val testFindImages = new WillFindImages(_ => "html-have-3-images")
val images = testFindImages("any-url")
// assertion

您可以看到类型别名FetchPage只是一个类型别名,因此我可以将其他String => String函数错误地传递给WillFindImages,所以我正在寻找类型安全溶液

然后我从scalaz听说Tagged typehttp://eed3si9n.com/learning-scalaz/Tagged+type.html

这个例子令人兴奋:

sealed trait KiloGram

def KiloGram[A](a: A): A @@ KiloGram = Tag[A, KiloGram](a)

val mass = KiloGram(20.0)

2 * mass

您可以看到此处的mass实际上是双20.0,但它有一些独特的类型。

我想用它来改进我的代码,但遗憾的是我无法找到办法。我试过了:

object FetchPage extends ((String => Try[String]) @@ FetchType)

但它提供了编译错误:

Error:(18, 51) class type required but String => scala.util.Try[String] with
    scalaz.Tagged[object_as_func.FetchType] found
object FetchPage extends ((String => Try[String]) @@ FetchType) {
                                                  ^

如何解决?

1 个答案:

答案 0 :(得分:2)

你使用什么scalaz版本?它在7.0.6和7.1.0中略有不同。以下是7.1.0的示例

 import scalaz.@@

  object PageFetcher

  type FetchPage = String => String
  type FindImages = String => List[String]

  val WillFetchPage: FetchPage @@ PageFetcher.type =
    scalaz.Tag[FetchPage, PageFetcher.type](url => "Content")

  class WillFindImages(fetchPage: FetchPage @@ PageFetcher.type) extends FindImages {
    def apply(url: String): List[String] = scalaz.Tag.unwrap(fetchPage)(url).grouped(1).toList
  }

  val images = new WillFindImages(WillFetchPage)("url")

  println(images)

  val testFetcher: FetchPage @@ PageFetcher.type =
    scalaz.Tag[FetchPage, PageFetcher.type](url => "TestContent")
  val testImages = new WillFindImages(testFetcher)("url")

  println(testImages)