【问题标题】:Passing State monad result form one step to another in a program + stop early在程序中将状态单子结果从一个步骤传递到另一个步骤+提前停止
【发布时间】:2019-10-27 05:15:23
【问题描述】:

我有这些步骤:

trait BlackjackSteps {
    def gamerTakesTwoCards(gamerName:String): State[Deck, Gamer]
    def dealerTakesTwoCards: State[Deck, Dealer]
    def isBlackjack(gamer: Gamer, dealer: Dealer): Option[Player]
    def gamerDrawsCards(gamer: Gamer): State[Deck, Gamer]
    def dealerDrawsCards(dealer: Dealer, gamer: Gamer): State[Deck, Dealer]
    def determineWinner(gamer: Gamer, dealer: Dealer): Player

    def program(gamerName:String): State[Deck, Player] = for {
      gamer <- gamerTakesTwoCards(gamerName)
      dealer <- dealerTakesTwoCards
      //winner = isBlackjack(gamer, dealer)
      gamerFinal <- gamerDrawsCards(gamer)
      dealerFinal <- dealerDrawsCards(dealer, gamerFinal)
      winnerFinal = determineWinner(gamerFinal, dealerFinal)
    } yield  winnerFinal
  }

两个问题:

  • 如何获得由 gamerTakesTwoCards 产生的牌组并将其传递给 DealerTakesTwoCards?

  • isBlackjack 可能会导致赢家,在这种情况下,我需要停止并返回赢家。我怎样才能改变上面的代码来做到这一点?

游戏:

  • 游戏玩家和庄家游戏
  • 他们都抽两张牌
  • 如果没有 21 名获胜者
  • 玩家一直抽牌直到 17 点
  • 不超过 21 分的最高玩家获胜!

完整代码在这里:https://bitbucket.org/jameskingconsulting/blackjack-scala/src/master/

编辑:

我已经去糖化了,只是为了弄清楚发生了什么:

def program(gamerName:String): State[Deck, Player] =
      gamerTakesTwoCards(gamerName).flatMap( gamer =>
        dealerTakesTwoCards.flatMap(dealer =>
          isBlackjack(gamer, dealer).fold(

            gamerDrawsCards(gamer).flatMap( gamerFinal =>
              dealerDrawsCards(dealer, gamerFinal).map( dealerFinal =>
                determineWinner(gamerFinal, dealerFinal)
              )
            )

          )(State.pure[Deck, Player])
        ))

【问题讨论】:

    标签: scala functional-programming monads scala-cats for-comprehension


    【解决方案1】:
    1. 无事可做。这就是重点。
    2. 无论isBlackjack 是返回None 还是Some,您都必须返回一个获胜者。无论哪种方式,您都必须返回State[Deck, Player]。例如,您可以在Option 上使用fold 来实现它,将成功案例映射到pure:

      def program(gamerName:String): State[Deck, Player] = for {
        gamer <- gamerTakesTwoCards(gamerName)
        dealer <- dealerTakesTwoCards
        winner <- isBlackjack(gamer, dealer).fold(for {
          gamerFinal <- gamerDrawsCards(gamer)
          dealerFinal <- dealerDrawsCards(dealer, gamerFinal)
          winnerFinal = determineWinner(gamerFinal, dealerFinal)
        } yield winnerFinal)(State.pure[Deck, Player])
      } yield winner
      

    【讨论】:

    • 谢谢,因为 (1) 我的代码中有一个错误,让我认为 Deck 没有正确传递,但现在它工作正常。我似乎无法想象的一件事是甲板从一个步骤转移到另一个步骤。你能分享一个链接来解释这是怎么发生的吗?
    • @jakstack Here 是一个很好的玩具示例。 State[S, A] 本质上只是 S =&gt; (A, S),即它采用旧状态,返回带有新状态的 A。给定一个State[S, A] 和一个f: A =&gt; State[S, B],您执行以下操作:您从第一个状态s0 开始并将其提供给State[S, A],它返回(a, s1),其中s1 是第一个修改的状态。现在您将f 应用到a 并使用更新后的状态s1 提供给它。这将返回一个b: B 和一个再次更新的状态s2。 (b, s2) 是最后返回的结果。
    • 谢谢,f: A => State[S, B] 是像 gamerTakesTwoCards 这样的 BlackjackSteps 中的步骤之一吗?
    • @jakstack 签名已经表明:gamerTakeTwoCards(s) 的类型为State[Deck, Gamer],如上所述,它本质上只是Deck =&gt; (Gamer, Deck) 的一个花哨名称。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    相关资源
    最近更新 更多