Created
January 20, 2022 18:15
-
-
Save joshuakfarrar/88e9d6ce13db3d07094d7c3263f723c5 to your computer and use it in GitHub Desktop.
using the StateT Monad, we are able to interleave IO into our recursive simulation of State transitions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val scala3Version = "3.1.0" | |
lazy val root = project | |
.in(file(".")) | |
.settings( | |
name := "cards n' stuff", | |
version := "0.1.0-SNAPSHOT", | |
scalaVersion := scala3Version, | |
libraryDependencies ++= Seq( | |
"com.novocode" % "junit-interface" % "0.11" % "test", | |
"org.typelevel" %% "cats-core" % "2.7.0", | |
"org.typelevel" %% "cats-effect" % "3.3.4" | |
) | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.util.Random | |
import cats.data.State | |
object Deck { | |
sealed trait Rank | |
case object Two extends Rank | |
case object Three extends Rank | |
case object Four extends Rank | |
case object Five extends Rank | |
case object Six extends Rank | |
case object Seven extends Rank | |
case object Eight extends Rank | |
case object Nine extends Rank | |
case object Ten extends Rank | |
case object Jack extends Rank | |
case object Queen extends Rank | |
case object King extends Rank | |
case object Ace extends Rank | |
sealed trait Suit | |
case object Hearts extends Suit | |
case object Clubs extends Suit | |
case object Diamonds extends Suit | |
case object Spades extends Suit | |
case class Card(rank: Rank, suit: Suit) | |
val standardDeck = Seq( | |
Card(Two, Hearts), | |
Card(Three, Hearts), | |
Card(Four, Hearts), | |
Card(Five, Hearts), | |
Card(Six, Hearts), | |
Card(Seven, Hearts), | |
Card(Eight, Hearts), | |
Card(Nine, Hearts), | |
Card(Ten, Hearts), | |
Card(Jack, Hearts), | |
Card(Queen, Hearts), | |
Card(King, Hearts), | |
Card(Ace, Hearts), | |
Card(Two, Clubs), | |
Card(Three, Clubs), | |
Card(Four, Clubs), | |
Card(Five, Clubs), | |
Card(Six, Clubs), | |
Card(Seven, Clubs), | |
Card(Eight, Clubs), | |
Card(Nine, Clubs), | |
Card(Ten, Clubs), | |
Card(Jack, Clubs), | |
Card(Queen, Clubs), | |
Card(King, Clubs), | |
Card(Ace, Clubs), | |
Card(Two, Diamonds), | |
Card(Three, Diamonds), | |
Card(Four, Diamonds), | |
Card(Five, Diamonds), | |
Card(Six, Diamonds), | |
Card(Seven, Diamonds), | |
Card(Eight, Diamonds), | |
Card(Nine, Diamonds), | |
Card(Ten, Diamonds), | |
Card(Jack, Diamonds), | |
Card(Queen, Diamonds), | |
Card(King, Diamonds), | |
Card(Ace, Diamonds), | |
Card(Two, Spades), | |
Card(Three, Spades), | |
Card(Four, Spades), | |
Card(Five, Spades), | |
Card(Six, Spades), | |
Card(Seven, Spades), | |
Card(Eight, Spades), | |
Card(Nine, Spades), | |
Card(Ten, Spades), | |
Card(Jack, Spades), | |
Card(Queen, Spades), | |
Card(King, Spades), | |
Card(Ace, Spades) | |
) | |
class Deck(val cards: Seq[Card] = standardDeck) { | |
def shuffle: Deck = new Deck(Random.shuffle(cards)) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats.effect.{ExitCode, IO, IOApp} | |
import cats.data.{State, StateT} | |
object Main extends IOApp { | |
import Deck._ | |
def describe(card: Card) = | |
s"${card.rank} of ${card.suit}" | |
def draw: StateT[IO, Deck, Option[Card]] = for { | |
deck <- StateT.get[IO, Deck] | |
_ <- StateT.modify[IO, Deck](_ => new Deck(deck.cards.drop(1))) | |
} yield deck.cards.headOption | |
def drawUntilEmpty(lastCard: Option[Card]): StateT[IO, Deck, Option[Card]] = for { | |
drawCard <- draw | |
_ <- StateT.liftF { | |
drawCard match { | |
case Some(card) => IO(println(s"got a card: ${describe(card)}")) | |
case None => IO(println("no more cards!")) | |
} | |
} | |
outcome <- drawCard match { | |
case Some(card) => drawUntilEmpty(Some(card)) | |
case None => StateT.liftF(IO(lastCard)) | |
} | |
} yield outcome | |
override def run(args: List[String]): IO[ExitCode] = | |
for { | |
_ <- drawUntilEmpty(None).run(new Deck().shuffle) | |
} yield ExitCode.Success | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@merlinorg, @hrhino, @zackjp: pick a card, any card