On this page:
check
try
let_  cc
begin
trace
....
....
time
#%parens
#%literal

6 Other Expression Forms🔗ℹ

expression

check:

  expr

  ~is expected_expr

 

expression

check:

  expr

  ~raises string_expr

Checks that expr produces the same result as expected_expr or raises an exception with an error message that contains the string produced by string_expr. Expressions expr and expected_expr must have the same type, while string_expr must have the type String. The type of the check expression is Void.

When the result does not match the expected result, then an error is printed, but evaluation continues.

> check:

    1+2

    ~is 3

- Void

> check:

    1/0

    ~raises "division by zero"

- Void

> check:

    1+2

    ~is 4

- Void

check: failed

  got: 3

  expected: 4

expression

try:

  expr

  ~catch:

    handle_expr

Returns the same result as expr, unless an exception is raised during the evaluation of expr, in which case handle_expr is evaluated and its result is returned. The type of expr and the type of handle_expr must be the same.

> try:

    1+2

    ~catch:

      0

- Int

3

> try:

    1/0

    ~catch:

      0

- Int

0

> try:

    error(#'example, "oops")

    ~catch:

      ["was", "an", "error"]

- Listof(String)

["was", "an", "error"]

expression

let_cc id:

  body

Returns the same result as body, but binds id to a function that represents the contination of let_cc expression. If id is called, whether before or after body is returned, the continuation of the call is discarded and replaced with the continuation represented by id.

> let_cc k:

    1 + k(2)

- Int

2

> 10 + (let_cc k:

          1 + k(2))

- Int

12

expression

begin:

  expr

  ...

Similar to block with multiple expressions in its body, but allowing any type for expressions that aren’t the last expression. The last expression in begin provides the type and result for the overall begin expression. The results of expressions before the last one are ignored, which generally is useful only when those expressions have some side effect.

> begin:

    1+2 // useless, because result is ignored

    3+4

- Int

7

def mutable counter = 0

fun bump():

  counter := counter + 1

  counter

> begin:

    bump() // first bump's result ignored

    bump()

- Int

2

expression

trace fun_expr:

  expr

Returns the value of expr, but while expr is being evaluated, traces calls and results for the function produced by fun_expr. The value of fun_expr must be a function as defined using def or fun; that is, fun_expr does not have to be an identifier, but it must have the same result as the defined identifier.

Tracing prints => for each function call, adding one additional = to the front of => for each nesting level. It prints <= before showing each result, adding one additional = to the end of <= for each nesting level. When a traced call has the same continuation as the previous traced call, the nesting depth is not increased, and no result is shown for the previous call (since it is the same as the new call’s result). When tracing lazy evaluation (see Lazy Mode), arguments and results may print as #<thunk>, indicating that an expression’s value has not been demanded, yet.

fun tail_sum(lst, accum):

  match lst

  | []: accum

  | cons(n, rst): tail_sum(rst, n + accum)

fun nontail_sum(lst):

  match lst

  | []: 0

  | cons(n, rst): n + nontail_sum(rst)

> trace tail_sum:

    tail_sum([1, 2, 3], 0)

- Int

=> tail_sum([1, 2, 3], 0)

=> tail_sum([2, 3], 1)

=> tail_sum([3], 3)

=> tail_sum([], 6)

<= 6

6

> trace nontail_sum:

    nontail_sum([1, 2, 3])

- Int

=> nontail_sum([1, 2, 3])

==> nontail_sum([2, 3])

===> nontail_sum([3])

====> nontail_sum([])

<==== 0

<=== 3

<== 5

<= 6

6

> trace tail_sum:

    nontail_sum([1, 2, 3])

- Int

6

expression

.... anything ...

 

expression

expr .... anything ...

 

type

....

The .... operator (with four dots) can be used as a prefix, infix, or suffix operator. The argument before an infix or suffix .... must be a valid expression, but anything after .... (in the same shrubbery group) is effectively commented out. Furthermore, the overall .... expression can have any type.

> ....

- ?_a

exn:fail:syntax: contract violation

  expected: (listof syntax?)

  given: [’....’]

> .... not sure what should go here! ....

- ?_a

exn:fail:syntax: contract violation

  expected: (listof syntax?)

  given: [’....’]

> ....:

    maybe return []?

    maybe call error?

- ?_a

exn:fail:syntax: contract violation

  expected: (listof syntax?)

  given: [’....’]

The .... operator also can be used as an “unknown” type that is incompatible with any other type, including another use of .... as a type.

> def x :: .... = 1

typecheck failed: .... vs. Int

expression

time: expr

Returns the result of expr, but before returning, prints information about how time passed when evaluating expr. Reported times are in milliseconds.

expression

#%parens (expr)

The #%parens expression form is generally not written out, but it is implicitly used whenever a Shplait program uses parentheses that are not function-call parentheses.

> (1 + 2)

- Int

3

> #%parens (1 + 2)

- Int

3

expression

#%literal literal

The #%literal expression form is generally not written out, but it is implicitly used whenever a Shplait program uses a literal value like 1, #false, or "apple".

> 1

- Int

1

> #%literal 1

- Int

1