On this page:
->
->*
forall*
lambda*
#%app
define
elim
define-type
case
case*
let
:  :
run
step
step-n
query-type
6.2.901.900

3.2 Sugar

The curnel forms are sort of terrible for actually writing code. Functions and applications are limited to single artity. Functions type must be specified using the dependent forall, even when the dependency is not used. Inductive elimination can only be done via the primitive eliminator and not via pattern matching. However, with the full force of Racket’s syntactic extension system, we can define not only simply notation, but redefine what application means, or define a pattern matcher that expands into the eliminator.

 (require cur/stdlib/sugar) package: cur
This library defines various syntactic extensions making Cur easier to write than writing raw TT.

syntax

(-> t1 t2)

( t1 t2)
A non-dependent function type Equivalent to (forall (_ : t1) t2), where _ indicates an variable that is not used.

Examples:

> (data And : (-> Type (-> Type Type))
    (conj : (forall (A : Type) (forall (B : Type) (-> A (-> B ((And A) B)))))))
> ((((conj Bool) Bool) true) false)

'((((conj Bool) Bool) true) false)

syntax

(->* t ...)

(→* t ...)
A non-dependent multi-arity function type that supports automatic currying.

Examples:

> (data And : (->* Type Type Type)
    (conj : (forall (A : Type) (forall (B : Type) (->* A B ((And A) B))))))
> ((((conj Bool) Bool) true) false)

'((((conj Bool) Bool) true) false)

syntax

(forall* (a : t) ... type)

(∀* (a : t) ... type)
A multi-arity function type that supports automatic currying.

Examples:

> (data And : (->* Type Type Type)
    (conj : (forall* (A : Type) (B : Type)
              (->* A B ((And A) B)))))
> ((((conj Bool) Bool) true) false)

'((((conj Bool) Bool) true) false)

syntax

(lambda* (a : t) ... body)

(λ* (a : t) ... body)
Defines a multi-arity procedure that supports automatic currying.

Examples:

> ((lambda (x : Bool) (lambda (y : Bool) y)) true)

'(λ (y1 : Bool) y1)

> ((lambda* (x : Bool) (y : Bool) y) true)

'(λ (y1 : Bool) y1)

syntax

(#%app f a ...)

Defines multi-arity procedure application via automatic currying.

Examples:

> (data And : (->* Type Type Type)
    (conj : (forall* (A : Type) (B : Type)
              (->* A B ((And A) B)))))
> (conj Bool Bool true false)

'((((conj Bool) Bool) true) false)

syntax

(define name body)

(define (name (x : t) ...) body)
Like the define provided by cur/curnel/redex-lang, but supports defining curried functions via lambda*.

syntax

(elim type motive-result-type e ...)

Like the elim provided by cur/curnel/redex-lang, but supports automatically curries the remaining arguments e ....

Examples:

> (require cur/stdlib/bool)
> (elim Bool Type (lambda (x : Bool) Bool)
    false
    true
    true)

'false

syntax

(define-type name type)

(define-type (name (a : t) ...) body)
Like define, but uses forall* instead of lambda*.

syntax

(case e [pattern maybe-IH body] ...)

 
pattern = constructor
  | 
  | (constructor (x : t) ...)
     
maybe-IH = 
  | IH: ((x : t) ...)
A pattern-matcher-like syntax for inductive elimination. Actually does not do pattern matching and relies on the constructors patterns being specified in the same order as when the inductive type was defined.

Examples:

> (require cur/stdlib/nat)
> (case z
    [z true]
    [(s (n : Nat))
     IH: ((_ : Bool))
     false])

'true

syntax

(case* type motive-result-type e (parameters ...) motive [pattern maybe-IH body] ...)

 
pattern = constructor
  | 
  | (constructor (x : t) ...)
     
maybe-IH = 
  | IH: ((x : t) ...)
A pattern-matcher-like syntax for inductive elimination that does not try to infer the type or motive. Necessary for more advanced types, like And, because case is not very smart.

Don’t worry about all that output from requiring prop

Examples:

> (require cur/stdlib/nat)
> (case* Nat Type z () (lambda (x : Nat) Bool)
    [z true]
    [(s (n : Nat))
     IH: ((_ : Bool))
     false])

'true

> (require cur/stdlib/prop)
> (case* And Type (conj Bool Nat true z) (Bool Nat)
    (lambda* (A : Type) (B : Type) (ab : (And A B)) A)
    [(conj (A : Type) (B : Type) (a : A) (b : B))
     IH: ()
     a])

'true

syntax

(let (clause ...) body)

 
clause = (id expr)
  | ((id : type) expr)
Evaluates the expressions expr from each clause, left to right, and binds them to each id. If a type is not given for the id, attempts to infer the type of the corresponding expr, raising a syntax error if no type can be inferred.

Examples:

> (let ([x Type]
        [y (λ (x : (Type 1)) x)])
    (y x))

'(Unv 0)

> (let ([x uninferrable-expr]
        [y (λ (x : (Type 1)) x)])
    (y x))

eval:20:0: cur: term is ill-typed:

  at: uninferrable-expr

  in: uninferrable-expr

syntax

(:: e type)

Check that expression e has type type, causing a type-error if not, and producing (void) if so.

Examples:

> (:: z Nat)
> (:: true Nat)

eval:22:0: ::: Term true does not have expected type Nat.

Inferred type was Bool

  in: (:: true Nat)

syntax

(run syn)

Like normalize/syn, but is a syntactic form which allows a Cur term to be written by computing part of the term from another Cur term.

Example:

> (lambda (x : (run (if true Bool Nat))) x)

'(λ (x1 : Bool) x1)

syntax

(step syn)

Like run, but uses step/syn to evaluate only one step and prints intermediate results before returning the result of evaluation.

Example:

> (step (plus z z))

((λ (n2 : Nat) (((((elim Nat (Unv 0)) (λ (x1 : Nat) Nat)) n2) (λ (x1 : Nat) (λ (ih-n1 : Nat) (s ih-n1)))) z)) z)

'z

syntax

(step-n natural syn)

Like step, but expands to natural calls to step.

Example:

> (step-n 3 (plus z z))

((λ (n2 : Nat) (((((elim Nat (Unv 0)) (λ (x1 : Nat) Nat)) n2) (λ (x1 : Nat) (λ (ih-n1 : Nat) (s ih-n1)))) z)) z)

(((((elim Nat (Unv 0)) (λ (x1 : Nat) Nat)) z) (λ (x1 : Nat) (λ (ih-n1 : Nat) (s ih-n1)))) z)

z

'z

syntax

(query-type expr)

Print the type of expr, at compile-time. Similar to Coq’s Check.

Example:

> (query-type Bool)

"Bool" has type "(Type 0)"