scala-expert

Expert guidance for Scala development, functional programming, Akka actors, and reactive systems.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "scala-expert" with this command: npx skills add personamanagmentlayer/pcl/personamanagmentlayer-pcl-scala-expert

Scala Expert

Expert guidance for Scala development, functional programming, Akka actors, and reactive systems.

Core Concepts

Scala Fundamentals

  • Immutability

  • Pattern matching

  • Case classes

  • Traits and mixins

  • Implicit conversions

  • For comprehensions

Functional Programming

  • Higher-order functions

  • Monads (Option, Either, Try)

  • Functors and Applicatives

  • Type classes

  • Pure functions

  • Referential transparency

Reactive Systems

  • Akka actors

  • Akka Streams

  • Akka HTTP

  • Play Framework

  • Cats Effect

  • ZIO

Scala Basics

// Case classes case class User(id: String, name: String, email: String, age: Int)

// Pattern matching def processUser(user: User): String = user match { case User(_, name, , age) if age < 18 => s"$name is a minor" case User(, name, , age) if age >= 65 => s"$name is a senior" case User(, name, _, _) => s"$name is an adult" }

// Options instead of null def findUser(id: String): Option[User] = { database.get(id) }

val userName = findUser("123") match { case Some(user) => user.name case None => "Unknown" }

// Or using map val name = findUser("123").map(_.name).getOrElse("Unknown")

// For comprehensions def getUserWithPosts(userId: String): Option[(User, List[Post])] = { for { user <- findUser(userId) posts <- findPosts(userId) } yield (user, posts) }

// Traits and mixins trait Serializable { def toJson: String }

trait Loggable { def log(message: String): Unit = println(s"[LOG] $message") }

case class Person(name: String, age: Int) extends Serializable with Loggable { def toJson: String = s"""{"name":"$name","age":$age}""" }

// Implicit classes (extension methods) implicit class StringOps(s: String) { def isValidEmail: Boolean = s.contains("@") && s.contains(".") }

"test@example.com".isValidEmail // true

Functional Programming

import cats._ import cats.implicits._

// Functor val numbers = List(1, 2, 3, 4, 5) val doubled = numbers.map(_ * 2)

// Applicative val result = (Option(1), Option(2), Option(3)).mapN { (a, b, c) => a + b + c }

// Monad (flatMap) def fetchUser(id: String): Future[Option[User]] = ??? def fetchPosts(userId: String): Future[List[Post]] = ???

val userWithPosts: Future[Option[(User, List[Post])]] = { fetchUser("123").flatMap { case Some(user) => fetchPosts(user.id).map(posts => Some((user, posts))) case None => Future.successful(None) } }

// Or with for-comprehension val result: Future[Option[(User, List[Post])]] = for { userOpt <- fetchUser("123") posts <- fetchPosts(userOpt.map(_.id).getOrElse("")) } yield userOpt.map(user => (user, posts))

// Either for error handling sealed trait Error case class NotFound(id: String) extends Error case class ValidationError(message: String) extends Error

def validateUser(user: User): Either[Error, User] = { if (user.email.isValidEmail) Right(user) else Left(ValidationError("Invalid email")) }

def saveUser(user: User): Either[Error, User] = { for { validated <- validateUser(user) saved <- database.save(validated) } yield saved }

// Type classes trait Show[A] { def show(a: A): String }

object Show { def apply[A](implicit sh: Show[A]): Show[A] = sh

implicit val stringShow: Show[String] = new Show[String] { def show(s: String): String = s }

implicit val intShow: Show[Int] = new Show[Int] { def show(i: Int): String = i.toString }

implicit def listShow[A: Show]: Show[List[A]] = new Show[List[A]] { def show(list: List[A]): String = { list.map(Show[A].show).mkString("[", ", ", "]") } } }

def print[A: Show](a: A): Unit = { println(Show[A].show(a)) }

Akka Actors

import akka.actor.typed._ import akka.actor.typed.scaladsl._

// Actor definition object UserActor { sealed trait Command final case class GetUser(id: String, replyTo: ActorRef[Response]) extends Command final case class CreateUser(user: User, replyTo: ActorRef[Response]) extends Command

sealed trait Response final case class UserFound(user: User) extends Response final case class UserNotFound(id: String) extends Response final case class UserCreated(user: User) extends Response

def apply(): Behavior[Command] = { Behaviors.setup { context => var users = Map.empty[String, User]

  Behaviors.receiveMessage {
    case GetUser(id, replyTo) =>
      users.get(id) match {
        case Some(user) =>
          replyTo ! UserFound(user)
        case None =>
          replyTo ! UserNotFound(id)
      }
      Behaviors.same

    case CreateUser(user, replyTo) =>
      users = users + (user.id -> user)
      replyTo ! UserCreated(user)
      Behaviors.same
  }
}

} }

// Using the actor val system: ActorSystem[UserActor.Command] = ActorSystem(UserActor(), "user-system")

import akka.actor.typed.scaladsl.AskPattern._ import akka.util.Timeout import scala.concurrent.duration._

implicit val timeout: Timeout = 3.seconds

val response: Future[UserActor.Response] = system.ask(ref => UserActor.GetUser("123", ref))

Akka Streams

import akka.stream._ import akka.stream.scaladsl._ import akka.actor.ActorSystem

implicit val system = ActorSystem("streams") implicit val materializer = ActorMaterializer()

// Simple stream val source = Source(1 to 10) val flow = Flow[Int].map(_ * 2) val sink = Sink.foreachInt

source.via(flow).runWith(sink)

// Backpressure handling val throttled = Source(1 to 100) .throttle(10, 1.second) .map { n => println(s"Processing $n") n * 2 } .runWith(Sink.ignore)

// Error handling val resilient = Source(1 to 10) .map { n => if (n == 5) throw new Exception("Error at 5") n * 2 } .recover { case e: Exception => -1 } .runWith(Sink.seq)

// Parallelism val parallel = Source(1 to 100) .mapAsync(parallelism = 4) { n => Future { // Async operation Thread.sleep(100) n * 2 } } .runWith(Sink.seq)

Akka HTTP

import akka.http.scaladsl.Http import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ import spray.json.DefaultJsonProtocol._

// JSON protocol case class User(id: String, name: String, email: String)

object JsonProtocol { implicit val userFormat = jsonFormat3(User) }

import JsonProtocol._

// Routes val routes = pathPrefix("api") { pathPrefix("users") { get { path(Segment) { userId => // GET /api/users/:userId complete(findUser(userId)) } ~ pathEnd { // GET /api/users complete(getAllUsers()) } } ~ post { pathEnd { // POST /api/users entity(as[User]) { user => complete(createUser(user)) } } } } }

// Start server val bindingFuture = Http().newServerAt("localhost", 8080).bind(routes)

Cats Effect / ZIO

import cats.effect._ import cats.effect.implicits._

// Pure functional effects with Cats Effect def fetchUser(id: String): IO[User] = IO { // Effectful computation database.get(id) }

def saveUser(user: User): IO[Unit] = IO { database.save(user) }

val program: IO[Unit] = for { user <- fetchUser("123") updated = user.copy(name = "Updated") _ <- saveUser(updated) } yield ()

// Error handling val safeProgram: IO[Either[Throwable, Unit]] = program.attempt

// Parallel execution val parallel: IO[List[User]] = { List("1", "2", "3") .parTraverse(id => fetchUser(id)) }

// ZIO import zio._

def fetchUserZIO(id: String): Task[User] = ZIO.attempt { database.get(id) }

val zioProgram: Task[Unit] = for { user <- fetchUserZIO("123") _ <- Console.printLine(s"Found user: ${user.name}") } yield ()

Best Practices

Functional Programming

  • Prefer immutability

  • Use pure functions

  • Avoid side effects

  • Use Option/Either over null/exceptions

  • Leverage type classes

  • Use for-comprehensions

  • Apply functional composition

Scala Style

  • Follow naming conventions

  • Use case classes for data

  • Prefer vals over vars

  • Use pattern matching

  • Avoid null

  • Use implicits carefully

  • Write idiomatic code

Performance

  • Use lazy evaluation

  • Stream large datasets

  • Avoid unnecessary allocations

  • Use tail recursion

  • Profile before optimizing

  • Consider parallelism

Anti-Patterns

❌ Using null ❌ Mutable state everywhere ❌ God objects ❌ Excessive implicits ❌ Not handling errors ❌ Blocking operations ❌ Not using type safety

Resources

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

python-expert

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

devops-expert

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

code-review-expert

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

typescript-expert

No summary provided by upstream source.

Repository SourceNeeds Review