archives

Liquid Metal project, Lime language: Java for FPGA co-processors

[corrected link, apologies] Liquid Metal, Lime:

We introduce Lime, a new Object-Oriented language that can be compiled for the JVM or into a synthesizable hardware description language. Lime extends Java with features that provide a way to carry OO concepts into efficient hardware. We detail an end-to-end system from the language down to hardware synthesis and demonstrate a Lime program running on both a conventional processor and in an FPGA.

Question concerning parameterization over literals

We're currently looking at something in BitC, and I'm wondering if there may be a simpler way. I'm concerned that we may have gotten stuck in a "we know how to do types now, so everything is a typing problem" sort of rut.

Background

In BitC, we have both vectors and arrays. The size of an array is part of its type, but we presently have no way to abstract over that size. This means that we cannot currently build a type class for something like (length expr) and instantiate a version of length that operates on arbitrary arrays. Perhaps more importantly, it means that we cannot express a low-level read function that puts data into an existing array in-place, because we cannot abstract over different possible array sizes.

After some head scratching, we concluded that there is no fundamental problem with extending typeclass-style constraints and instantiation to incorporate instantiation over literals. The underlying observation is that every literal can be considered to be a member of some singleton type, and you can then abstract over that type in the usual way. So far so good.

But as we dug into it a bit, we somehow moved from "abstraction over literals" to "abstraction over literal-associated singleton types". For example, our old specification of the array type constructor was:

    (array T e)

where e must be a literal of type word. The new specification seems to have become:

    (array T T.len)

where "T.len" is required to be a singleton literal type. In this case, that would be a constrained type of the form 'a\(Literal 'a word). So an abstracted "read" function would now be something like:

read: (forall ((Literal 'len Word))
        (fn Stream (by-ref (mutable (array byte 'len))) 'len -> Word)

meaning that read accepts a stream, an array by reference, and a length guaranteed to match the array length, and returns the number of characters read.

All well and good, but from a usability perspective we still want to be able to write something simple like:

(array char 2)

For the moment, there are only a very few syntactic contexts where this would make sense, and Swaroop has proposed that we accept (interchangebly) either a singleton literal type or a value of singleton literal type and "lift" the value to its type in these syntactic contexts. And I think all of that will work.

The Question

While all of this ought to work, it feels like we are going around Robin Hood's barn here. Are there other languages that have dealt with this, and if so, what should we look at to understand better what has previously been done?

Type Checking with Open Type Functions

Type Checking with Open Type Functions by Tom Schrijvers, Simon Peyton-Jones, Manuel M. T. Chakravarty, and Martin Sulzmann

We report on an extension of Haskell with open type-level functions and equality constraints that unifies earlier work on GADTs, functional dependencies, and associated types. The contribution of the paper is that we identify and characterise the key technical challenge of entailment checking; and we give a novel, decidable, sound, and complete algorithm to solve it, together with some practically-important variants. Our system is implemented in GHC, and is already in active use.

Related to GHC/Type families, which can be an important optimization technique when specializing the types. Type families allow greater control over types. I guess they didn't like having C++ templates having any advantage with associated types. Personally, it reminds me of some of the power afforded by ML parameterized functors.

(via reddit and 2 Minute intro to Associated Types/Type Families).