Abstracting over arithmetic

Image for post
Image for post
Counting every which way

This blog post will deal with an experimental approach to higher order functions at compile time, at the type level. It’s motivated in part by my previous post on ternary Nat, Counting to Infinity at Compile time.

You needn’t understand the details of TNat (or its binary cousin BNat), just know that they are different implementations of the concept behind shapeless.Nat that do not use the usual Succ.

A typeclass which takes arguments (type parameters) and maybe returns a type (an abstract type member implemented by the typeclass’s implicits). It will almost certainly follow the aux pattern. …


Higher better faster longer

Image for post
Image for post

We saw in a previous blog post of mine an introduction to counting at compile time in scala, using the conventional Nat type.

Unfortunately, Nat is slow. Really, really slow, and there are hard limits on what we can make the scala compiler do, as it currently stands.

For example, here are some rough and ready and entirely-unscientific benchmarks I’ve just run on approximate compile times for the Sum typeclass we defined last time. The numbers would be completely different on your machine, but probably to the right order of magnitude:

Sum    | Approx Time
------------------------
3+6 | 0s
8+8 | 0s
10+7 | 0s
12+12 | 2s
15+15 | <does not complete>
17+4 | 1s
20+5 | 7s
20+8 | 104s
22+11 | <does not complete>
22+22 | <does not…


Image for post
Image for post
1, 2, 3, 4, …

Counting at compile time is one of the world’s simple pleasures. We have taken the scala compiler and hacked something in to it to make it do things it really doesn’t look like it should be doing.

The standard approach of ‘counting at compile time’ utilises a type commonly called Nat. It’s available in libraries such as shapeless. We have types available, that look like this: type _13 = <something> — this represents the number 13. <something> is yet to be revealed.

Through type-class trickery and a clever definition of something we can make the compiler perform magic for us, and turn two types such as _13 and _3 into a third type _16 by ‘adding’ them together, all at compile time. You can, of course, also make it do any other arithmetic operation you can dream of, if you have the time to implement it. …


In a previous blog post I introduced the scala library Alphabet Soup, for type-level transformations.

It provides a mapping between arbitrarily nested types, provided the compiler can calculate a path between them, all powered with gratitude by Generic from shapeless.

A quick example:

Target here could be any combination of the atomic source types, in any order and in any nesting. It works in exactly the same way for case classes and hlists, in both source and target position, too.

What else can it do?

Data Injections

We saw in the previous blog post that a particular use-case might be centred around manipulating similar case classes into one another. …


Image for post
Image for post

The library alphabet-soup can be found here.

Alphabet-soup is a scala library to provide faster compiler-time type-mixing, to reduce boilerplate and the cognitive overhead of reading and writing canonical code.

If there’s only one way to write a piece of code, why do we have to write it? The compiler should do it for us.

Caveat

One major difference about alphabet-soup’s approach to the usual type-transformation libraries is that it is entirely type based and not name based. If you map a case class to a case class, it does not care what the
field names are, only the types. …


Using free monads to control the execution of asynchronous tasks in Scala

This blog post will assume terminology from the functional scala library Cats. It is easily applicable to Scalaz, too.

Libraries like Cats and Scalaz give you a verb ‘traverse’, for easier handling of combinations of wrapper types.

It allows you to turn something clunky like this:

into this:

That is, it does the map and the sequence for you. It applies the function to the collection, and pulls the wrapper type through to the outside.

Of course it’s not limited to Future and Seq. The ‘collection’ type can be anything that is “traversable” (lists, options, matrices, tuples, trys — it’s a supertype of foldable). …


Escaping Union type contexts safely

Goal and ideal syntax

In a previous blog post I introduced a way to get unboxed arbitrary arity union types in scala. We can write

foo allows an Int or a String to be passed to it, and nothing else.

But escaping the union context, ie getting the Int or the String out again from our generic T, wasn’t safe. We had to do this:

The above is not checked by the compiler, either for exhaustivity (if we’d missed Int it wouldn’t tell us) nor precision (if we included an extra type we didn’t need it wouldn’t tell us).

But it is certainly the easiest way to naively extract our original value again. …


How to pass sorting all the way through your Scala/Slick stack

When writing our project, we wanted to pass a static sorting object all the way through our stack from the API (where it was parsed automatically) to Slick, and have the database results be sorted automatically without any extra input from the end-user (ie you, the feature-developer).

(In this post I will assume you are familiar with Slick 3 and will always have the appropriate slick implicits and classes in scope.)

It isn’t obvious how to make slick do this automatic sorting for us. Imagine this table set up:

Just a table to store my dogs in. Now imagine I had a static Sorting type, and I wanted to sort a dog query by an object of type Sorting which I’d been supplied by our…


Preventing `data-too-wide’ SQL exceptions in Scala

Most strings that you store in a traditional SQL database have a maximum length allowed. This can frequently cause problems, since this maximum length isn’t known by your code.

You might have some checks dotted around, maybe on your API or DB layer, that only sensible length strings get into your system — but you probably don’t have them for every single field. Mutating strings, such as adding two fields together, also invalidates such checks — it will likely just cause a run-time error. One of the nice things about a type checker and functional programming in particular is that it enables and encourages you to remove entire classses of exceptions from your code. …

About

James Phillips

Functional developer, typelevel enthusiast https://www.typechecked.io

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store