gpt4 book ai didi

scala - 如何在 scala 中将这个 future /状态概念实现为 monad

转载 作者:行者123 更新时间:2023-12-04 12:49:13 25 4
gpt4 key购买 nike

我正在尝试为比赛(如体育赛事)结果实现一个容器,以便我可以在其他比赛的获胜者之间创建比赛。这个概念接近于 future 的单子(monad),因为它包含一个要定义的值,也接近于状态单子(monad),因为它隐藏了状态变化。作为该主题的初学者,我已经在 scala 中实现了一个肯定可以改进的初始版本。我添加了一个我不确定是否是个好主意的 get 方法,到目前为止,创建值的唯一方法是 Unknown(null)这并不像我希望的那样优雅。你认为我可以做些什么来改进这个设计?

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
}

更新 :当前实现的使用示例如下
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))
}
})
}

还有一个测试片段:
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"));

更新 - 当前想法:因为我的笔记本电脑坏了,所以我没有太多时间来处理这个问题,但我认为为感兴趣的人编写到目前为止的 monad 会很有用:
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 = {}
}

我摆脱了 set & get,现在 TBD 类改为接收一个函数,该函数将定义提供值或 null 如果仍未定义。这个想法对 map 方法很有效,但是其余的方法都有细微的错误。

最佳答案

对于一个简单的方法,你不需要单子(monad),部分应用就足够了:

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

这是一个起点,我很确定它可以进一步完善。也许我们会在那里找到难以捉摸的单子(monad)。但我认为一个应用仿函数就足够了。
稍后我会再给一个通行证...

关于scala - 如何在 scala 中将这个 future /状态概念实现为 monad,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8107619/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com