Skip to content

Commit

Permalink
Merge branch 'main' into signal-underflow-error
Browse files Browse the repository at this point in the history
  • Loading branch information
Jobhdez committed Mar 4, 2024
2 parents a4a252c + 237da98 commit 429e5fa
Show file tree
Hide file tree
Showing 23 changed files with 1,138 additions and 52 deletions.
17 changes: 16 additions & 1 deletion coalton.asd
Expand Up @@ -161,18 +161,21 @@
(:file "complex")
(:file "elementary")
(:file "dyadic")
(:file "dual")))
(:file "dual")))
(:file "randomaccess")
(:file "cell")
(:file "iterator")
(:file "optional")
(:file "result")
(:file "tuple")
(:file "lisparray")
(:file "list")
(:file "vector")
(:file "char")
(:file "string")
(:file "slice")
(:file "hashtable")
(:file "queue")
(:file "monad/state")
(:file "ord-tree")
(:file "ord-map")
Expand Down Expand Up @@ -205,6 +208,17 @@
(:file "impl-default"
:if-feature (:or :coalton-portable-bigfloat (:not :sbcl)))))

(asdf:defsystem #:coalton/library/computable-reals
:description "A Coalton interface for computable-reals (https://github.com/stylewarning/computable-reals)"
:author "Coalton contributors (https://github.com/coalton-lang/coalton)"
:license "MIT"
:version (:read-file-form "VERSION.txt")
:pathname "library/computable-reals"
:depends-on (#:coalton
#:computable-reals)
:serial t
:components ((:file "computable-reals")))

(asdf:defsystem #:coalton/testing
:author "Coalton contributors (https://github.com/coalton-lang/coalton)"
:license "MIT"
Expand Down Expand Up @@ -304,6 +318,7 @@
(:file "utilities")
(:file "tarjan-scc-tests")
(:file "reader-tests")
(:file "error-tests")
(:file "parser-tests")
(:file "type-inference-tests")
(:file "fundep-tests")
Expand Down
113 changes: 110 additions & 3 deletions docs/coalton-lisp-interop.md
Expand Up @@ -41,7 +41,7 @@ Release mode freezes most structures and optimizes them.

### Pitfalls of Having Two Modes

Unfortunately, having two modes may mean one inadvertently depend on the behavior in one mode that is not supported in the other. We advise testing your code against both modes.
Unfortunately, having two modes may mean that a user might inadvertently depend on the behavior of one mode that is not supported in the other. We advise testing your code against both modes.

### Developing the compiler

Expand Down Expand Up @@ -113,13 +113,66 @@ The pragma `(repr :lisp)` helps achieve Lisp compatibility of structures regardl

**HALF-HEARTED PROMISE**: For each non-nullary constructor (say `Ctor1`), a `setf`-able accessor function called `<class-name>/<ctor-name>-_<k>` will be defined for the `k`th member of that constructor. For the example above, suppose that `Ctor1` has two fields. Then the accessor functions `FOO/CTOR1-_0` and `FOO/CTOR1-_1` will be defined. (*Note*: The naming here is subject to change.)

### Simple enumerations with `(REPR :ENUM)`

Types that are a just a disjoint union of nullary constructors can be represented internally as Lisp symbols by using `(REPR :ENUM)`. This can be used for both Lisp interoperation matters as well as certain efficiency matters.

For example, we could represent the class of plane traveler like so:

```
(repr :enum)
(define-type TravelerClass
Economy
Business
First)
```

These will be compiled into symbols:

```
COALTON-USER> (coalton (make-list Economy Business First))
(TRAVELERCLASS/ECONOMY TRAVELERCLASS/BUSINESS TRAVELERCLASS/FIRST)
COALTON-USER> cl::(mapcar #'type-of *)
(COMMON-LISP:SYMBOL COMMON-LISP:SYMBOL COMMON-LISP:SYMBOL)
```

### Wrapper types with `(REPR :TRANSPARENT)`

Types with a single construtor consisting of a single field can be annotated with `(REPR :TRANSPARENT)`. This guarentees the wrapper type does not exist at runtime. The constructor function will still be generated, but it will be the identity function.

### Passing Lisp types through Coalton with `(REPR :NATIVE T)`
For example, we could represent an 8-bit gray value like so:

```
(repr :transparent)
(define-type Gray (Gray U8))
```

At runtime, a `Gray` value would just be a single byte.

### Passing Lisp types through Coalton with `(REPR :NATIVE)`

Coalton types can be unboxed lisp types under the hood with `(REPR :NATIVE <type>)`, where `<type>` is a Common Lisp type.

For example, we could wrap Common Lisp's `cl:random-state` objects like so:

```
(repr :native cl:random-state)
(define-type RandomState)
(declare make-state (Unit -> RandomState))
(define (make-state)
(lisp RandomState ()
(cl:make-random-state cl:t)))
(declare random (RandomState -> Integer -> Integer))
(define (random rs n)
(lisp Integer (rs n)
(cl:random n rs)))
```

Here, we used `lisp` to actually construct, type, and return our `RandomState` object, since our `define-type` doesn't itself have constructors.

Coalton types can be unboxed lisp types under the hood with `(repr :native T)`. See [`Vector`](https://github.com/coalton-lang/coalton/blob/main/library/vector.lisp) for an example.
See [`Vector`](https://github.com/coalton-lang/coalton/blob/main/library/vector.lisp) for a more extensive example.

## Promises of `define`

Expand Down Expand Up @@ -210,3 +263,57 @@ Here, the values of the parameters `a` and `b` are captured for use inside of th
As with almost any "foreign function interface" (especially those interfacing with C), there's lots of potential for type errors to be made that Coalton simply cannot check for at compile time. We recommend being extra cautious and being liberal with `check-type`s and other assertions when putting a value into the hands of Coalton-managed code.

Always be vigilant about _all_ possible return types of Lisp functions. Lisp, being a dynamically typed language, is sometimes lax about the possible return types, especially as they relate to the input type. Things like numerical contagion, `nil`, and error conditions can be serious sources of type errors.

## Recipes for calling Coalton functions from inside a Coalton-Calls-Lisp Bridge

The simplest example is calling a function without type class constraints. This allows you to call it directly from lisp:
```
(coalton-toplevel
(declare int-square (Integer -> Integer))
(define (int-square x)
"Returns the square of an Integer."
(* x x))
(define (print-int-square x)
(lisp String (x)
(cl:format cl:nil "~a squared = ~a" x (int-square x)))))
```
Functions with type class constraints cannot be called this way, but instead must be called with a nested lisp form containing the argument:
```
(coalton-toplevel
(declare num-square ((Num :a) => :a -> :a))
(define (num-square x)
"Returns the square of an object of any type with a defined instance of num."
(* x x))
(define (print-num-square1 x)
(lisp String (x)
(cl:format cl:nil "~a squared = ~a" x (coalton (num-square (lisp :a () x)))))))
```
If you have a function with no input, Coalton declares it as a function taking `Unit` as input. Thus, it must be wrapped in a Coalton form:
```
(coalton-toplevel
(declare spell-2 (Unit -> String))
(define (spell-2)
"two")
(define (how-do-you-spell-2)
(lisp String ()
(cl:format cl:nil "2 is spelled '~a'" (coalton (spell-2))))))
```
Lambda/anonymous functions in Coalton `let` bindings can be used from Lisp, as long they are unconstrained by a type class:
```
(coalton-toplevel
(define (lambda-print-square x)
(let ((declare square (Integer -> Integer))
(square (fn (a)
(* a a))))
(lisp :a (x square)
(cl:format cl:nil "~a squared = ~a" x (call-coalton-function square x))))))
```



4 changes: 2 additions & 2 deletions examples/small-coalton-programs/src/freecalc.lisp
Expand Up @@ -55,7 +55,7 @@ we map over."
(free:liftf (InputE id)))

;;
;; This lets us define programs in our arithemtic langauge
;; This lets us define programs in our arithmetic language
;;

(define a-program
Expand All @@ -67,7 +67,7 @@ we map over."
(pure res2)))

;;
;; We now define an interpretr for our language. Uses a natural
;; We now define an interpreter for our language. Uses a natural
;; transformation from the free monad over our expression functor
;; into a State monad. We use a vector of numbers for our inputs.
;;
Expand Down
29 changes: 29 additions & 0 deletions library/computable-reals/README.md
@@ -0,0 +1,29 @@
# Computable Reals

This library is built on [computable-reals](https://github.com/stylewarning/computable-reals).

### Creal

The primary type is a `Creal`, a wrapper on the computable-reals type of the same name.

As stated in the computable-reals README:

"Computable real numbers `x` are interpreted as (potentially) infinite fractions in base 2 that are specified through a rule for computation of an integer `a` with `|(2^k)*x - a| <= 1` for any `k>=0`."

### Instances:

`Eq` and `Ord` have been implemented in order to fulfill the needs of the `Num` typeclass, though they are not exact. Their definitions are shaky because they can only be verified up to an arbitrary, specified precision. The precision threshold for `Creal` can be accessed using the library function `comparison-threshold` and changed using `set-comparison-threshold!`. The default precision is `106`.

Other instances defined:

- `Num`
- `Reciprocable`
- `Exponentiable`
- `Radical`
- `Trigonometric`
- `Complex`
- `Polar`
- `Elementary`
- Typical `Into` instances


0 comments on commit 429e5fa

Please sign in to comment.