Skip to content

Instantly share code, notes, and snippets.

@frenchy64
Last active April 3, 2020 21:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frenchy64/073c99f0ecf50045222ac22afe763e8c to your computer and use it in GitHub Desktop.
Save frenchy64/073c99f0ecf50045222ac22afe763e8c to your computer and use it in GitHub Desktop.
typed.clj/spec Clojurists Together Application

Application for Clojurists Together open source project funding. See more details and an example application at https://www.clojuriststogether.org/open-source/.

We will automatically reuse your application for the next 4 funding rounds, unless you let us know otherwise. We will email you before each funding round closes to confirm you're still available.

Who are you?

Ambrose Bonnaire-Sergeant

What project are you applying for?

typed.clj/spec: type-like specs

Who is applying? How are you related to the project?

Ambrose Bonnaire-Sergeant, the creator and maintainer of Typed Clojure.

What are you wanting to achieve with this funding?

The first iteration of typed.clj/spec centered on generatively testing polymorphic functions, with much success -- for example, we can now generatively testing transducers, and variable-arity higher-order functions (like comp, map). eg., here's the spec for identity.

(s/def ::identity
  (all :binder (binder :x (bind-tv))
         :body
         (s/fspec :args (s/cat :x (tv :x))
                  :ret (tv :x))))

To generatively test that clojure.core/identity satisfies this, simply call (s/valid? ::identity identity).

Using this robust foundation, I want to explore the design space around typed.clj/spec. I will simultaneously investigate several promising areas, some of which are listed below.

Generatively testing macro expansions

I want to express (and test!) properties of macros like:

  • (if e1 e2 e3) returns e2 if its e1 is true
  • (let [x e1] e2) returns e2 after evaluating it with x mapped to e1

To sketch how this might be possible, here are the main differences between testing functions and macros.

Testing functions via fspec involves:

  1. Generating values for :args
  2. Applying :args to function
  3. Ensure return value satisfies :ret (and :fn)

I want to move this idea to the level of macros. Roughly, to check a macro, you:

  1. Generating programs for :args
  2. Splice :args into a macro form
  3. Ensure result of evaluating form satisfies :ret

Generatively testing properties of functions

I want to generatively test properties of functions like:

  • forall f,g,h. (comp (comp f g) h) == (comp f (comp g h))
    • "comp is associative"
  • forall f. (comp identity f) == (comp f identity)
    • "clojure.core/identity is the identity of comp"

The interesting parts are how to generate f, g, h. We can start with existing polymorphic infrastructure from typed.clj/spec.

Misc ideas

  • generate polymorphic functions (eg., generate (fn [x] x) for the spec of identity)
  • how to s/instrument polymorphic functions
  • polymorphic specs for Associative values (eg., how to write a spec for all arities of assoc?)
  • specs for Atoms & Channels

Why is this project important to the Clojure community?

typed.clj/spec is a fresh perspective on how to use clojure.spec. It gives programmers a level of specificity that rivals type systems, without the burden of static type checking.

Do you receive any other funding to work on this project?

Yes. These sources provide revenue for general Typed Clojure maintenance.

Have you been personally impacted by the COVID-19 crisis? How?

No.

Are you part of a group that is affected by systemic bias, particularly in technology? If so, can you elaborate?

No.

Anything else we should know?

No.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment