On this page:
class
instance
with-instance
with-instances
splicing-with-instance
splicing-with-instances
instantiate
8.12

3.1 Defining Classes and Instances🔗ℹ

A class is an abstract collection of names with optional default values.

Algebraic Racket’s classes are a lot like Haskell’s type classes without the typing constraints. They allow abstract design patterns like monads with do-notation to be expressed simply and in a generic way that makes sense for Racket.

The class form declares an abstract class and its members.

> (class Eq
    [== (.. not /=)]
    [/= (.. not ==)]
    minimal ([==] [/=]))

Using an uninstantiated member is a syntax error.

> ==

eval:43:14: ==: no instance for Eq

  in: ==

> (/= 1 0)

eval:44:14: /=: no instance for Eq

  in: (/= 1 0)

The instance form produces an object that holds class member definitions.

> (define-syntax StringEq (instance Eq [== string=?]))
> (define-syntax NumberEq (instance Eq [/= (|| < >)]))

Attempting to define an incomplete instance is a syntax error.

> (define-syntax BadEq (instance Eq))

eval:58:35: instance: Not a minimal definition

  in: (instance Eq extends ())

The with-instance form temporarily instantiates the members of an instance.

> (with-instance StringEq
    (and (== "abcde" "abcde")
         (/= "hello" "world")))

#t

> (with-instance NumberEq
    (and (== 1 1)
         (/= 2 3)))

#t

The with-instance form can prefix the names it binds so multiple instances of the same class can be used together.

> (with-instance [S: StringEq]
    (with-instance [N: NumberEq]
      (and (S:== "abc" "abc")
           (N:== 123 123))))

#t

The with-instances form offers a cleaner syntax for working with multiple instances.

> (define-syntax EqEq (instance Eq [== eq?]))
> (with-instances (EqEq
                   [S: StringEq]
                   [N: NumberEq])
    (and (== + +) (S:== "?" "?") (N:== 0 0)))

#t

syntax

(class class-id member-decl-or-def ...+ maybe-minimal)

 
member-decl-or-def = [member-id]
  | [member-id def-expr]
     
maybe-minimal = 
  | minimal ([member-id ...+] ...)
Creates a new class and transformer bindings related to it.

A class form with n members defines n+1 names:

Example:
> (class Continuation
    [call]
    [abort (φ x (error (format "abort: ~a" x)))]
    minimal ([call]))
> (call)

eval:127:16: call: no instance for Continuation

  in: (call)

> (abort 'no-op)

eval:128:16: abort: no instance for Continuation

  in: (abort (quote no-op))

The minimal directive, when present, constrains valid instances to only those that provide at least one of the minimal member-id sets.

Example:
> (define-syntax BadContinuation
    (instance Continuation [abort void]))

eval:138:7: instance: Not a minimal definition

  in: (instance Continuation extends () (abort void))

syntax

(instance class-id maybe-extends [member-id def-expr] ...+)

 
maybe-extends = 
  | extends (instance-id ...)
Produces an instance descriptor that represents a run-time implementation of the class bound to class-id with its member-ids extended or overridden by def-exprs.

The extends directive, when present, recursively imports the members of the instance-ids and the instances they extend.

Examples:
> (define current-esc (make-parameter #f))
> (define current-con (make-parameter #f))
> (define ((current-abort param msg) . xs)
    (if (param) ($ (param) xs) (error msg)))

> (define-syntax EscapeContinuation
    (instance Continuation
      [call (φ f (call/ec (φ esc (parameterize ([current-esc esc]) (f)))))]
      [abort (current-abort current-esc "no escape continuation")]))
> (define-syntax CurrentContinuation
    (instance Continuation
      [call (φ f (call/cc (φ con (parameterize ([current-con con]) (f)))))]
      [abort (current-abort current-con "no current continuation")]))

syntax

(with-instance instance-id/optional-prefix expr ...+)

syntax

(with-instances (instance-id/optional-prefix ...) expr ...+)

 
instance-id/optional-prefix = instance-id
  | [prefix-id instance-id]
Evaluates the exprs with the members of the class-ids instantiated according to the instances bound to the instance-ids.

If any prefix-ids are given, they are prepended to the names of the members defined by the corresponding instance-ids.

Examples:
> (with-instance EscapeContinuation
    (call (λ () (println 'START) (abort 'ESCAPE) (println 'DONE))))

'START

'ESCAPE

> (with-instance CurrentContinuation
    (call (λ () (abort 1 2) 3)))

1

2

Like with-instance and with-instances, except that in a definition context, the body forms are spliced into the enclosing definition context (in the same way as for begin).

Examples:
> (splicing-with-instance EscapeContinuation
    (define (f x)
      (call (λ () (abort `(ESC ,x))))))
> (f 1)

'(ESC 1)

> (splicing-with-instance [C: CurrentContinuation]
    (define (g x)
      (C:call (λ () (C:abort `(ABORT ,x))))))
> (g 2)

'(ABORT 2)

syntax

(instantiate instance-id)

(instantiate prefix instance-id)
Defines the members of instance-id with optional prefix for the remainder of the containing module or top level.

Example:
> (module inst algebraic/racket/base
    (class Eq
      [== (.. not /=)]
      [/= (.. not ==)]
      minimal ([==] [/=]))
    (define-syntax EqEq (instance Eq [== eq?]))
    (define-syntax StringEq (instance Eq [== string=?]))
    (instantiate EqEq)
    (instantiate S: StringEq)
    (== 'A 'A)
    (S:/= "a" "b"))
> (require 'inst)

#t

#t