agentsclimarketplace

Run2 scala type classes

Skill cxcscmu/SkillLearnBench/skills/b2-self-feedback-claude-sonnet-4-6/python-scala-translation/run2_scala-type-classes

Translating Python Protocol, ABC, and isinstance dispatch to Scala traits, overloaded methods, and functor/monad abstractions.From its SKILL.md

Install
npx -y skills add cxcscmu/SkillLearnBench --skill run2_scala-type-classes

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

4.6 KB, ~1.1k tokens by cl100k_base, as published. Nobody here has run it

Scala Traits, Overloading, and Functors (vs Python Protocol/ABC/isinstance)

Python Protocol → Scala Trait

Python structural typing (duck typing):

@runtime_checkable
class Tokenizable(Protocol):
    def to_token(self) -> str: ...

Scala uses nominal typing — classes must explicitly declare extends Tokenizable:

trait Tokenizable {
  def toToken: String
}
  • No @runtime_checkable — Scala trait membership is checked at compile time
  • Method name convention: toToken (camelCase) not to_token

Python ABC → Scala Abstract Class

class BaseTokenizer(ABC, Generic[T]):
    @abstractmethod
    def tokenize(self, value: T) -> Token: ...
    def tokenize_batch(self, values: Iterable[T]) -> Iterator[Token]:
        for v in values: yield self.tokenize(v)
abstract class BaseTokenizer[T] {
  def tokenize(value: T): Token                          // abstract (no body)
  def tokenizeBatch(values: Iterable[T]): Iterator[Token] =
    values.iterator.map(tokenize)                        // concrete default
}
  • Methods without body are abstract — no @abstractmethod annotation needed
  • values.iterator.map(tokenize) is lazy — same semantics as Python generator

Python isinstance Dispatch → Scala Method Overloading

Python runtime dispatch with type checks:

def tokenize(self, value: Any) -> Token:
    if value is None: return Token("NULL", TokenType.NULL)
    if isinstance(value, (str, bytes)): return self._string_tokenizer.tokenize(value)
    if isinstance(value, (int, float, Decimal)): return self._numeric_tokenizer.tokenize(value)
    if isinstance(value, (datetime, date)): return self._temporal_tokenizer.tokenize(value)

Scala compile-time overloading:

final class UniversalTokenizer {
  private val stringTokenizer   = new StringTokenizer()
  private val numericTokenizer  = new NumericTokenizer()
  private val temporalTokenizer = new TemporalTokenizer()

  def tokenize(value: String):        Token = stringTokenizer.tokenize(value)
  def tokenize(value: Array[Byte]):   Token = stringTokenizer.tokenizeBytes(value)
  def tokenize(value: Int):           Token = numericTokenizer.tokenizeInt(value)
  def tokenize(value: Double):        Token = numericTokenizer.tokenizeDouble(value)
  def tokenize(value: BigDecimal):    Token = numericTokenizer.tokenize(value)
  def tokenize(value: LocalDateTime): Token = temporalTokenizer.tokenize(value)
  def tokenize(value: LocalDate):     Token = temporalTokenizer.tokenizeDate(value)
  def tokenize(value: Tokenizable):   Token = Token(value.toToken, TokenType.STRUCTURED)
  def tokenizeNull: Token = Token("NULL", TokenType.NULL)   // null has no value in Scala
}
  • Each overload is resolved at compile time — no runtime overhead
  • None → tokenizeNull (separate method, since Scala null is not a type)

TokenFunctor and TokenMonad

class TokenFunctor[T](private val _value: T) {
  def get: T = _value
  def map[B](f: T => B): TokenFunctor[B]           = new TokenFunctor(f(_value))
  def flatMap[B](f: T => TokenFunctor[B]): TokenFunctor[B] = f(_value)
  def getOrElse[B >: T](default: => B): B = Option(_value).getOrElse(default)
}

Key improvements over Python:

  • map and flatMap are properly typed with B — not Any
  • get is the primary value accessor
  • getOrElse uses call-by-name default — only evaluated if needed
  • [B >: T] lower bound in getOrElse preserves type safety
class TokenMonad[T](value: T) extends TokenFunctor[T](value) {
  def ap[B](funcWrapped: TokenMonad[T => B]): TokenMonad[B] =
    new TokenMonad(funcWrapped.get(get))
}

object TokenMonad {
  def pure[T](value: T): TokenMonad[T] = new TokenMonad(value)
}
  • pure lives in companion object — replaces Python @classmethod
  • ap properly typed: accepts TokenMonad[T => B], returns TokenMonad[B]

TokenRegistry: Handler Pipeline

Python for/else semantics (first successful handler wins):

for handler in self._handlers:
    result = handler(item)
    if result is not None:
        results.append(result); break
else:
    results.append(None)

Scala with lazy iterator short-circuit:

handlers.iterator.flatMap(h => h(item)).nextOption()
  • h(item) returns Option[Token]
  • flatMap on Iterator[Option[Token]] flattens to Iterator[Token], skipping None
  • .nextOption() takes only the first result — lazy, so remaining handlers NOT evaluated
  • Returns Option[Token] — None if all handlers returned None

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.