2011-11-12 29 views
7

Tôi đang cố gắng triển khai vùng chứa cho kết quả phù hợp (như trong thể thao) để tôi có thể tạo kết quả phù hợp giữa người chiến thắng của các trận đấu khác. Khái niệm này là gần với những gì một monads trong tương lai là vì nó chứa một giá trị được xác định, và cũng gần với một nhà nước monad vì nó ẩn thay đổi trạng thái. Chủ yếu là một người ăn xin về chủ đề tôi đã thực hiện một phiên bản ban đầu trong scala đó là chắc chắn không thể thay đổi. Tôi đã thêm một phương thức có được mà tôi không chắc chắn là một ý tưởng tốt, và cho đến nay cách duy nhất để tạo ra một giá trị sẽ là Unknown(null) mà không phải là thanh lịch như tôi hy vọng. Bạn nghĩ tôi có thể làm gì để cải thiện thiết kế này?cách triển khai khái niệm tương lai/trạng thái này dưới dạng đơn nguyên trong scala

case class Unknown[T](t : T) { 
    private var value : Option[T] = Option(t) 
    private var applicatives: List[T => Unit] = Nil 

    def set(t: T) { 
    if (known) { 
     value = Option(t) 
     applicatives.foreach(f => f(t)) 
     applicatives = Nil 
    } else { 
     throw new IllegalStateException 
    } 
    } 

    def get : T = value.get 

    def apply(f: T => Unit) = value match { 
    case Some(x) => f(x); 
    case None => applicatives ::= f 
    } 

    def known = value == None 
} 

CẬP NHẬT: một ví dụ sử dụng của việc thực hiện hiện sau

case class Match(val home: Unknown[Team], val visit: Unknown[Team], val result: Unknown[(Int, Int)]) { 
    val winner: Unknown[Team] = Unknown(null) 
    val loser: Unknown[Team] = Unknown(null) 

    result.apply(result => { 
    if (result._1 > result._2) { 
     home.apply(t => winner.set(t)) 
     visit.apply(t => loser.set(t)) 
    } else { 
     home.apply(t => loser.set(t)) 
     visit.apply(t => winner.set(t)) 
    } 
    }) 
} 

Và một đoạn thử nghiệm:

val definedUnplayedMatch = Match(Unknown(Team("A")), Unknown(Team("B")), Unknown(null)); 
val definedPlayedMatch = Match(Unknown(Team("D")), Unknown(Team("E")), Unknown((1,0))); 
val undefinedUnplayedMatch = Match(Unknown(null), Unknown(null), Unknown(null)); 

definedUnplayedMatch.winner.apply(undefinedUnplayedMatch.home.set(_)) 
definedPlayedMatch.winner.apply(undefinedUnplayedMatch.visit.set(_)) 
undefinedUnplayedMatch.result.set((3,1)) 
definedUnplayedMatch.result.set((2,4)) 
undefinedUnplayedMatch.winner.get must be equalTo(Team("B")); 
undefinedUnplayedMatch.loser.get must be equalTo(Team("D")); 

CẬP NHẬT - HIỆN IDEA: tôi đã không có nhiều thời gian để giải quyết vấn đề này vì laptop của tôi bị hỏng, nhưng tôi sẽ rất hữu ích khi viết đơn nguyên Tôi có cho đến nay đối với những người quan tâm:

sealed abstract class Determine[+A] { 
    def map[B](f: A => B): Determine[B] 
    def flatMap[B](f: A => Determine[B]): Determine[B] 
    def filter(p: A => Boolean): Determine[A] 
    def foreach(b: A => Unit): Unit 
} 
final case class Known[+A](value: A) extends Determine[A] { 
    def map[B](f: A => B): Determine[B] = Known(f(value)) 
    def flatMap[B](f: A => Determine[B]): Determine[B] = f(value) 
    def filter(p: A => Boolean): Determine[A] = if (p(value)) this else Unknown 
    def foreach(b: A => Unit): Unit = b(value) 
} 
final case class TBD[A](definer:() => A) extends Determine[A] { 
    private var value: A = _ 

    def map[B](f: A => B): Determine[B] = { 
    def newDefiner(): B = { 
     f(cachedDefiner()) 
    } 
    TBD[B](newDefiner) 
    } 

    def flatMap[B](f: A => Determine[B]): Determine[B] = { 
    f(cachedDefiner()) 
    } 

    def filter(p: A => Boolean): Determine[A] = { 
    if (p(cachedDefiner())) 
     this 
    else 
     Unknown 
    } 

    def foreach(b: A => Unit): Unit = { 
    b(cachedDefiner()) 
    } 

    private def cachedDefiner(): A = { 
    if (value == null) 
     value = definer() 
    value 
    } 
} 
case object Unknown extends Determine[Nothing] { 
    def map[B](f: Nothing => B): Determine[B] = this 
    def flatMap[B](f: Nothing => Determine[B]): Determine[B] = this 
    def filter(p: Nothing => Boolean): Determine[Nothing] = this 
    def foreach(b: Nothing => Unit): Unit = {} 
} 

Tôi đã thoát khỏi những bộ & có được và bây giờ là lớp TBD nhận thay vì một chức năng mà sẽ xác định cung cấp giá trị hoặc null nếu vẫn không xác định. Ý tưởng này hoạt động tốt cho phương pháp bản đồ, nhưng phần còn lại của các phương pháp có lỗi tinh tế.

+0

Không đáng lo ngại về việc triển khai, bạn có thể đưa ra một số ví dụ về cách bạn * sử dụng * một đơn nguyên như vậy bằng cách sử dụng 'flatMap' hoặc' for' comprehensions không? Việc triển khai của bạn hiện thiếu phương thức 'flatMap' để xác định ngữ nghĩa trên đơn vị của bạn. – huynhjl

+0

Tôi đã cập nhật câu hỏi bằng cách sử dụng thử nghiệm tôi đang cung cấp cho nó ngay bây giờ. Tôi nhận ra rằng việc triển khai của tôi quá vụng về để tận dụng lợi thế của sự hiểu biết vào lúc này, về cơ bản nó là một cổng của một mô hình quan sát trong Java thiếu đường cú pháp. – ilcavero

+0

Nó không phải là rất rõ ràng từ ví dụ của bạn những gì bạn đang cố gắng để thực hiện trong việc đưa ra các [A] không rõ monad. Bạn có thể cho chúng tôi biết thêm một chút về ứng dụng sẽ sử dụng thư viện này không? – dyross

Trả lời

2

Đối với một phương pháp đơn giản, bạn không cần phải monads, với ứng dụng một phần là đủ:

//some utilities 
type Score=(Int,Int) 
case class MatchResult[Team](winner:Team,loser:Team) 

//assume no ties 
def playMatch[Team](home:Team,away:Team)(score:Score)= 
    if (score._1>score._2) MatchResult(home,away) 
    else MatchResult(away,home) 

//defined played match 
val dpm= playMatch("D","E")(1,0) 
//defined unplayed match, we'll apply the score later 
val dum= playMatch("A","B")_ 

// a function that takes the dum score and applies it 
// to get a defined played match from an undefined one 
// still is a partial application of match because we don't have the final result yet 
val uumWinner= { score:Score => playMatch (dpm.winner,dum(score).winner) _ } 
val uumLoser= { score:Score => playMatch (dpm.loser,dum(score).loser) _} 

//apply the scores 
uumWinner (2,4)(3,1) 
uumLoser (2,4)(0,1) 


//scala> uumWinner (2,4)(3,1) 
//res6: MatchResult[java.lang.String] = MatchResult(D,B) 
//scala> uumLoser (2,4)(0,1) 
//res7: MatchResult[java.lang.String] = MatchResult(A,E) 

Đây là một điểm khởi đầu, tôi khá chắc chắn rằng nó có thể được cải thiện. Có lẽ ở đó chúng ta sẽ tìm thấy một đơn vị khó nắm bắt. Nhưng tôi nghĩ rằng một functor applicative sẽ là đủ. Tôi sẽ cấp một thẻ khác sau ...

+0

đây là một sự thay thế rất thú vị, điểm yếu chính tôi thấy là nó áp đặt một trật tự trong định nghĩa kết quả, và cũng có thể nó khó hình dung hơn tiến trình của khung mà không có đối tượng Match. – ilcavero

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