Skip to content
cccskills
FreePublished on GitHub

nw-fp-scala

Scala 3 language-specific patterns with ZIO, Cats Effect, and opaque types

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md6.5 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

FP in Scala 3 -- Functional Software Crafter Skill

Cross-references: fp-principles | fp-domain-modeling | property-based-testing

When to Choose Scala

  • Best for: JVM with full FP power | large-scale systems | data engineering | richest effect ecosystem
  • Not ideal for: small teams wanting simplicity | Android (use Kotlin) | teams allergic to OO/FP duality

[STARTER] Quick Setup

cs install scala3-compiler scala3-repl sbt
sbt new scala/scala3.g8 && cd order-service
# Add zio, zio-test, scalacheck to build.sbt
sbt compile && sbt test

[STARTER] Type System for Domain Modeling

Choice Types and Record Types

enum PaymentMethod:
  case CreditCard(cardNumber: String, expiryDate: String)
  case BankTransfer(accountNumber: String)
  case Cash

case class Customer(
  customerId: CustomerId,
  customerName: CustomerName,
  customerEmail: EmailAddress
)

Case classes provide structural equality, copy, and pattern matching for free.

[STARTER] Domain Wrappers (Opaque Types) -- Zero Cost

object OrderDomain:
  opaque type OrderId = Int
  object OrderId:
    def apply(value: Int): OrderId = value
  extension (id: OrderId) def value: Int = id

  opaque type EmailAddress = String
  object EmailAddress:
    def from(raw: String): Either[ValidationError, EmailAddress] =
      if raw.contains("@") then Right(raw)
      else Left(InvalidEmail(raw))

Inside defining scope, alias is transparent. Outside, only exported operations available.

[INTERMEDIATE] Composition Style

For-Comprehensions (Monadic Chaining)

def placeOrder(raw: RawOrder): Either[OrderError, Confirmation] =
  for
    validated <- validateOrder(raw)
    priced    <- priceOrder(validated)
    confirmed <- confirmOrder(priced)
  yield confirmed

Error Accumulation (Cats Validated or ZIO)

import cats.data.Validated
import cats.syntax.all.*

def validateCustomer(raw: RawCustomer): ValidatedNel[ValidationError, Customer] =
  (validateName(raw.name), validateEmail(raw.email), validateAddress(raw.address))
    .mapN(Customer.apply)

[ADVANCED] Effect Management

ZIO vs Cats Effect

ZIO: ZIO[R, E, A] with built-in typed errors, DI (ZLayer), batteries-included. Cats Effect: IO[A], minimal type-class-based, Typelevel ecosystem (http4s, FS2, Doobie). Pick one and stay consistent.

ZIO Hexagonal Architecture

trait OrderRepository:
  def findOrder(id: OrderId): Task[Option[Order]]
  def saveOrder(order: Order): Task[Unit]

def placeOrder(raw: RawOrder): ZIO[OrderRepository & PricingService, OrderError, Confirmation] =
  for
    repo      <- ZIO.service[OrderRepository]
    validated <- ZIO.fromEither(validateOrder(raw))
    priced    <- ZIO.fromEither(priceOrder(validated))
    _         <- repo.saveOrder(priced)
  yield Confirmation(priced.orderId)

// Adapter
class PostgresOrderRepository(ds: DataSource) extends OrderRepository:
  def findOrder(id: OrderId): Task[Option[Order]] = ZIO.attemptBlocking { /* query */ }
  def saveOrder(order: Order): Task[Unit] = ZIO.attemptBlocking { /* insert */ }

val appLayer: ZLayer[Any, Nothing, OrderRepository & PricingService] =
  PostgresOrderRepository.layer ++ PricingServiceLive.layer

Cats Effect / Tagless Final

trait OrderRepository[F[_]]:
  def findOrder(id: OrderId): F[Option[Order]]

def placeOrder[F[_]: Monad](repo: OrderRepository[F])(raw: RawOrder): F[Either[OrderError, Confirmation]] =
  for
    validated <- Monad[F].pure(validateOrder(raw))
    result <- validated match
      case Left(err) => Monad[F].pure(Left(err))
      case Right(v)  => repo.findOrder(v.orderId).map(_.toRight(OrderNotFound))
  yield result

[INTERMEDIATE] Testing

Frameworks: ScalaCheck (PBT) | ZIO Test (integrated PBT + unit) | ScalaTest (BDD) | MUnit (lightweight). See property-based-testing for detailed PBT patterns.

Property Test (ScalaCheck)

import org.scalacheck.Properties
import org.scalacheck.Prop.forAll

object OrderSpec extends Properties("Order"):
  property("serialization round-trips") = forAll { (order: Order) =>
    deserialize(serialize(order)) == Right(order)
  }
  property("validated orders have positive totals") = forAll { (raw: RawOrder) =>
    validateOrder(raw) match
      case Left(_)     => true
      case Right(valid) => valid.total.value > 0
  }

[ADVANCED] Idiomatic Patterns

Enum-Based State Machines

enum OrderState:
  case Unvalidated(raw: RawOrder)
  case Validated(order: ValidatedOrder)
  case Priced(order: PricedOrder)
  case Confirmed(confirmation: Confirmation)

def transition(state: OrderState, command: OrderCommand): Either[OrderError, OrderState] =
  (state, command) match
    case (OrderState.Unvalidated(raw), OrderCommand.Validate) =>
      validateOrder(raw).map(OrderState.Validated(_))
    case (OrderState.Validated(order), OrderCommand.Price) =>
      priceOrder(order).map(OrderState.Priced(_))
    case _ => Left(InvalidTransition(state, command))

Extension Methods for Domain Operations

extension (order: PricedOrder)
  def totalWithTax(taxRate: BigDecimal): Money = Money(order.total.value * (1 + taxRate))
  def isHighValue: Boolean = order.total.value > 1000

Maturity and Adoption

  • Ecosystem fragmentation: ZIO vs Cats Effect creates split ecosystem. Libraries often target one or the other. Mixing is painful.
  • Slow compilation: Scala 3 faster than 2 but still significantly slower than Kotlin or Java. Keep modules small; consider Mill over sbt.
  • Complexity reputation: Scala's power (implicits, type-level programming, macros) creates wildly varying codebases. Establish team conventions early.
  • Migration burden: Scala 2 to 3 migration non-trivial. Ecosystem has mostly caught up by 2025-2026.

Common Pitfalls

  1. Ecosystem fragmentation: Pick one effect ecosystem (ZIO or Cats) and stay consistent. Mixing creates dependency conflicts.
  2. Implicit/given complexity: Keep given instances close to their types. Deep resolution chains produce cryptic errors.
  3. OO/FP tension: Prefer case classes + enums + pure functions over class hierarchies with mutable state.
  4. Slow compilation: Use sbt incremental compilation, keep modules small, consider Mill for faster builds.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation

The English summary is being prepared. Showing the original description.

nWave-ai/nWave622Updated Sep 16, 2026

Review dimensions for validating agent quality - template compliance, safety, testing, and priority validation

The English summary is being prepared. Showing the original description.

nWave-ai/nWave622Updated Sep 16, 2026

Review dimensions for acceptance test quality - happy path bias, GWT compliance, business language purity, coverage completeness, walking skeleton user-centricity, priority validation, observable behavior assertions, traceability coverage, and walking skeleton boundary proof

The English summary is being prepared. Showing the original description.

nWave-ai/nWave622Updated Sep 16, 2026

Detailed 5-phase workflow for creating agents - from requirements analysis through validation and iterative refinement

The English summary is being prepared. Showing the original description.

nWave-ai/nWave622Updated Sep 16, 2026

5-layer testing approach for agent validation including adversarial testing, security validation, and prompt injection resistance

The English summary is being prepared. Showing the original description.

nWave-ai/nWave622Updated Sep 16, 2026

Architectural style selection decision matrices, trade-off analysis, structural enforcement rules, and combination patterns. Load when choosing or evaluating architecture styles.

The English summary is being prepared. Showing the original description.

nWave-ai/nWave622Updated Sep 16, 2026

See all skills by nWave-ai

Report a problem with this skill