2015-12-31 13 views
5

Chúng tôi đã sử dụng bộ biến đổi đơn vị WriterT trên Futures với hy vọng sẽ nhận được nhiều nhật ký được sắp xếp hơn từ một ứng dụng không đồng bộ, nhưng chúng tôi gặp phải một số rắc rối.Scalaz: bộ lọc nào đóng vai trò trong | @ |?

Nếu tôi biên dịch ứng dụng bên dưới, tôi nhận được lỗi sau. Xin lưu ý rằng đây không phải là cảnh báo về withFilter.

[lỗi] Giá trị bộ lọc không phải là thành viên của scalaz.WriterT [scala.concurrent.Future, Danh sách [Chuỗi], String]

Tại sao | @ | cần bộ lọc ở đây? Scalaz có cung cấp một chuyển đổi tiềm ẩn cho trường hợp này không?

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.Future 
import scalaz._ 
import Scalaz._ 

object Failure extends App { 

    type LoggedT[F[_], A] = WriterT[F, List[String], A] 
    type LoggedFuture[A] = LoggedT[Future, A] 

    //this is the applicative behavior that we want WriterT to preserve 
    val example = for { 
    z <- (Future("left") |@| Future("right")) { (x: String, y: String) => x + " " + y } 
    } yield z 

    example.onSuccess { case x => println(x) } 

    val test = for { 
    z: String <- (Future("left").liftM[LoggedT] |@| Future("right").liftM[LoggedT]) { (x: String, y: String) => x + " " + y } 
    } yield z 

    test.value.onSuccess { case x => println(x) } 

} 

Lỗi này xảy ra với phiên bản Scala: 2.11.7 và Scalaz phiên bản: 7.2.0

Trả lời

7

Nó thường thuận tiện để sử dụng thư viện phản ánh của reify để xem những gì đang xảy ra trong desugaring (đây là lần duy nhất tôi 'd bao giờ đề nghị nhập khẩu bất cứ thứ gì từ scala.reflect.runtime, và ngay cả trong trường hợp này chỉ trong REPL quá trình phát triển):

scala> import scala.reflect.runtime.universe.reify 
import scala.reflect.runtime.universe.reify 

scala> reify(for { x: Int <- Option(1) } yield x) 
res5: reflect.runtime.universe.Expr[Option[Int]] = 
Expr[scala.Option[Int]](Option.apply(1).withFilter(((check$ifrefutable$1) => check$ifrefutable$1: @unchecked match { 
    case (x @ (_: Int)) => true 
    case _ => false 
})).map(((x: Int) => x))) 

vấn đề là loại hợp cụ thể mô hình phù hợp trong cho-hiểu. Mặc dù trình biên dịch sẽ xác minh rằng kết quả phù hợp là an toàn (ví dụ: for { x: String <- Option(1) } yield x sẽ không biên dịch), nó vẫn được giải thích cho hoạt động lọc. Tôi không chắc tại sao - có lẽ đó là một lý do cho nó, và thậm chí có một cơ hội nhỏ mà đó là một lý do chính đáng.

Bạn nhận được thông báo về filter vì đó là phương sách cuối cùng của trình biên dịch trong trường hợp này. Trước tiên, nó sẽ cố gắng desugar gọi tới withFilter và nếu không tìm thấy withFilter, nó sẽ sử dụng filter (ít nhất trong việc triển khai của thư viện bộ sưu tập thường kém hiệu quả hơn trong các trường hợp như thế này). Trong trường hợp của WriterT nó không tìm thấy (kể từ khi lọc một nhà văn không có ý nghĩa trong trường hợp chung), do đó, nó than phiền về một trong những cuối cùng nó đã cố gắng.

Giải pháp là không sử dụng đối sánh kiểu chữ. Viết một đồng bằng cũ for { z <- ... } yield z và mọi thứ sẽ hoạt động tốt. Trong thực tế, I'd suggest not ever using type-case matching — đó là cách lén lút nhất cho các vấn đề liên quan đến thời gian chạy phản chiếu để kết thúc trong mã của bạn. Trong trường hợp này hoạt động sẽ được kiểm tra tại thời gian biên dịch (ít nhất là trong các trường hợp hiển nhiên), nhưng nó vẫn không cần thiết và có khả năng kém hiệu quả hơn.

+1

Tôi đã thêm chú thích loại chỉ để giúp loại IntelliJ kiểm tra mã. Tôi sẽ không bao giờ đoán nó có thể là điều này có hại. –

Các vấn đề liên quan