Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Scala 3 language-specific patterns with ZIO, Cats Effect, and opaque types
.claude/skills/nwave-ai-nw-fp-scala/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 57% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 36% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 64% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 31% | 0% |
Cross-references: fp-principles | fp-domain-modeling | pbt-jvm
bashcs 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
scalaenum 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.
scalaobject 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.
scaladef placeOrder(raw: RawOrder): Either[OrderError, Confirmation] = for validated <- validateOrder(raw) priced <- priceOrder(validated) confirmed <- confirmOrder(priced) yield confirmed
scalaimport 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)
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.
scalatrait 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
scalatrait 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
Frameworks: ScalaCheck (PBT) | ZIO Test (integrated PBT + unit) | ScalaTest (BDD) | MUnit (lightweight). See pbt-jvm for detailed PBT patterns.
scalaimport 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 }
scalaenum 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))
scalaextension (order: PricedOrder) def totalWithTax(taxRate: BigDecimal): Money = Money(order.total.value * (1 + taxRate)) def isHighValue: Boolean = order.total.value > 1000
given instances close to their types. Deep resolution chains produce cryptic errors.Other measured skills in the registry, with their headline benchmark lift.