将 State monad 结果从程序中的一个步骤传递到另一个步骤 + 提前停止

Passing State monad result form one step to another in a program + stop early

我有这些步骤:

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
  }

两个问题:

游戏:

完整代码在这里: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])
        ))
  1. 无事可做。这就是重点。
  2. 无论isBlackjackreturn是NoneSome。无论哪种方式,您都必须 return 一个 State[Deck, Player]。例如,您可以通过 Option 上的 fold 实现它,将 success-case 映射到 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