scalaintermediate
Functional State Management
Manage state purely with State monad: stack-based state, random number generation, and game state.
scalaPress ⌘/Ctrl + Shift + C to copy
// Simple State monad implementation
case class State[S, A](run: S => (A, S)):
def map[B](f: A => B): State[S, B] =
State { s =>
val (a, s1) = run(s)
(f(a), s1)
}
def flatMap[B](f: A => State[S, B]): State[S, B] =
State { s =>
val (a, s1) = run(s)
f(a).run(s1)
}
object State:
def get[S]: State[S, S] = State(s => (s, s))
def set[S](s: S): State[S, Unit] = State(_ => ((), s))
def modify[S](f: S => S): State[S, Unit] = State(s => ((), f(s)))
def pure[S, A](a: A): State[S, A] = State(s => (a, s))
// Stack operations
type Stack[A] = List[A]
def push[A](item: A): State[Stack[A], Unit] =
State.modify(item :: _)
def pop[A]: State[Stack[A], Option[A]] =
State { stack =>
stack match
case head :: tail => (Some(head), tail)
case Nil => (None, Nil)
}
def peek[A]: State[Stack[A], Option[A]] =
State(stack => (stack.headOption, stack))
def stackSize[A]: State[Stack[A], Int] =
State(stack => (stack.size, stack))
// Random number generator
case class RNG(seed: Long):
def next: (Int, RNG) =
val newSeed = (seed * 6364136223846793005L + 1442695040888963407L) & Long.MaxValue
val n = (newSeed >>> 16).toInt
(n, RNG(newSeed))
def nextInt: State[RNG, Int] = State(_.next)
def nextIntBound(bound: Int): State[RNG, Int] =
nextInt.map(n => (n & Int.MaxValue) % bound)
def nextBool: State[RNG, Boolean] =
nextInt.map(_ % 2 == 0)
def rollDice: State[RNG, Int] =
nextIntBound(6).map(_ + 1)
// Game state
case class GameState(score: Int, lives: Int, level: Int)
def addScore(points: Int): State[GameState, Unit] =
State.modify(g => g.copy(score = g.score + points))
def loseLife: State[GameState, Boolean] =
for
_ <- State.modify[GameState](g => g.copy(lives = g.lives - 1))
g <- State.get[GameState]
yield g.lives > 0
def nextLevel: State[GameState, Int] =
for
_ <- State.modify[GameState](g => g.copy(level = g.level + 1))
g <- State.get[GameState]
yield g.level
@main def run(): Unit =
// Stack
val stackProgram = for
_ <- push(1)
_ <- push(2)
_ <- push(3)
top <- pop[Int]
size <- stackSize[Int]
yield (top, size)
val (result, finalStack) = stackProgram.run(Nil)
println(s"Popped: ${result._1}, Size: ${result._2}, Stack: $finalStack")
// Random
val diceRolls = for
d1 <- rollDice
d2 <- rollDice
d3 <- rollDice
yield List(d1, d2, d3)
val (rolls, _) = diceRolls.run(RNG(42))
println(s"Dice rolls: $rolls")
// Game
val game = for
_ <- addScore(100)
_ <- addScore(50)
alive <- loseLife
lvl <- nextLevel
g <- State.get[GameState]
yield (alive, lvl, g)
val (gameResult, finalState) = game.run(GameState(0, 3, 1))
println(s"Alive: ${gameResult._1}, Level: ${gameResult._2}")
println(s"Final: $finalState")Use Cases
- Pure state transformations
- Game state management
- Reproducible random generation
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
scalabeginner
Collections Map Filter Fold Operations
Master Scala collections: map, flatMap, filter, fold, groupBy, partition, and zip operations.
Best for: Data transformation and aggregation
#scala#collections
scalaintermediate
For-Comprehensions and Monadic Composition
Use for-comprehensions with Option, Either, Future, and custom monads for elegant composition.
Best for: Chaining optional computations
#scala#for-comprehension
scalaadvanced
Type Class Pattern Implementation
Implement the type class pattern in Scala 3: define, provide instances, and use with extension methods.
Best for: Ad-hoc polymorphism without inheritance
#scala#type-class
scalaadvanced
Cats Effect IO Monad Basics
Use Cats Effect IO for pure functional effects: sequencing, error handling, resource management.
Best for: Pure functional effect management
#scala#cats-effect