• Stars
    star
    108
  • Rank 321,259 (Top 7 %)
  • Language
    Scala
  • License
    GNU Lesser Genera...
  • Created almost 8 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Scala library for free applicative schemas capable of parsing/rendering sums-of-products data structures.

Xenomorph

Xenomorph is a Scala library for building well-typed descriptions of other Scala data structures, from which one can then automatically derive serialization, parsing, and generation functions. Implementations are currently provided for producing argonaut DecodeJson and EncodeJson instances, as well as scalacheck Gen values. Similar facilities for scodec, protobuf, and whatever else might be useful will be coming as time permits and interest demands.

Getting Started

Xenomorph is still awaiting an initial release, so for now you'll have to build it locally for yourself.

Creating a Schema

Begin with the data type for which you wish to create a schema. Here's an example:

import monocle.macros._

@Lenses case class Person(
  name: String, 
  birthDate: Instant,
  roles: Vector[Role]
)

sealed trait Role

case object User extends Role {
  val prism = GenPrism[Role, User.type]
}

@Lenses case class Administrator(department: String, subordinateCount: Int) extends Role
object Administrator {
  val prism = GenPrism[Role, Administrator]
}

In this example, you can see:

  • A simple record type Person
  • A sum type Role with two constructors, User and Administrator

To build a schema for the Person type, we will use the Scalaz applicative constructor at arity 3 (^^) as shown below:

import scalaz.syntax.apply._
import xenomorph.Schema._
import xenomorph.json.JType._

val personSchema: Schema[JSchema, Person] = rec(
  ^^(
    required("name", jStr, Person.name.asGetter),
    required(
      "birthDate", jLong.composeIso(Iso(new Instant(_:Long))((_:Instant).getMillis)), 
      Person.birthDate.asGetter
    ),
    required("roles", jArray(roleSchema), Person.roles.asGetter)
  )(Person.apply _)
)

The schema for the Role sum type is created as a nonempty list of alternatives, each of which provides a prism from the sum type to the underlying data type associated with each constructor. In the case of the User case object, the underlying schema is that of the empty object, which is isomorphic to Unit. () is the empty tuple, so we treat the empty record as the Unit schema constructor.

val roleSchema: Schema[JSchema, Role] = Schema.oneOf(
  alt[JSchema, Role, User.type](
    "user", 
    Schema.const(User),
    User.prism
  ) ::
  alt[JSchema, Role, Administrator](
    "administrator", 
    rec(
      ^(
        required("department", jStr, Administrator.department.asGetter),
        required("subordinateCount", jInt, Administrator.subordinateCount.asGetter)
      )(Administrator.apply _)
    ),
    Administrator.prism
  ) :: shapeless.HNil
)

This schema is constructed using the JType GADT to define the set of recognized primitive types. However, the set of primitive types is a user-definable feature at the time of schema construction.

Once you have a Schema value, you can use it to produce parsers, serializers, and generators.

import argonaut._
import xenomorph.json.ToJson._
import xenomorph.json.FromJson._
import xenomorph.scalacheck.ToGen._

val personJson: Json = personSchema.toJson(person) 

val parsedPerson: Option[Person] = personSchema.fromJson(personJson).toOption

val personGen: Gen[Person] = personSchema.toGen

Contributors

Kris Nuttycombe (@nuttycom) Antonio Alonso Dominguez Doug Clinton

More Repositories

1

sbt-proguard-plugin

A plugin for SBT to facilitate the use of ProGuard to create single jars for SBT-managed projects.
Scala
47
star
2

aftok

Haskell
30
star
3

commons-pipeline

The github home of the Apache commons-pipeline project, a project that I originated in 2004.
Java
12
star
4

scala-exercises

Some simple functional programming exercises in Scala
Scala
8
star
5

lambdaconf-2016

HTML
6
star
6

pickle

A delightful little markup language.
Scala
5
star
7

purescript-schema

FreeAp-based schema for sums-of-products data types in PureScript
PureScript
5
star
8

colorlife-games

A platform for competetive variants of Conway's Game of Life written in Scala
Scala
5
star
9

salt

A collection of Scala utility classes to spice up any project
Scala
4
star
10

nuttycom.github.io

HTML
4
star
11

thx.schema

A very simple applicative parsing library for haXe dynamic values.
Haxe
4
star
12

thx.json

A JSON AST for Haxe.
Haxe
3
star
13

hs-curriculum

Haskell
2
star
14

scala_world-2017

Slides and sample code for Scala World, 2017 talk.
HTML
2
star
15

lambdaconf-2014-workshop

Exercises for "Complexity and Reasoning in Functional Programming" at LambdaConf 2014
Shell
2
star
16

haskell-voting

Implementations of various voting system algorithms in Haskell
Haskell
2
star
17

lambdaconf-2014

Slides and source code for LambdaConf 2014
HTML
2
star
18

bjug-20100810

Slides & code from Boulder JUG talk 10 August 2010
Scala
1
star
19

scalaz-depend

A skeleton project depending on scalaz
Scala
1
star
20

lambdaconf-2015

Slides for "Parametricity: The Essence of Information Hiding"
HTML
1
star
21

thx.lens

Lenses & prisms for Haxe data structures.
Haxe
1
star