8.12

1.2 Modules, Variables, and Functions🔗ℹ

A Rhombus module, which implements a program or a library, always starts #lang rhombus. If you write an expression at the top of a module, then its value gets printed out.

#lang rhombus

 

1+4  // prints 5

 

"Hello, world!"  // prints "Hello, world!", including the quotes

If you have installed the rhombus-prototype package, then you can run Rhombus modules in DrRacket or by supplying the file path to racket on the command line.

Ways to define names in a module include def and fun. The def form defines an immutable variable, and it expects an identifier to define followed by either = or a block. The fun form defines a function when followed by an identifier, parentheses around argument names, and then a block. Function calls have the usual shape: a function name (or, more generally, an expression that produces a function) followed by comma-separated arguments in parentheses.

#lang rhombus

 

def fahrenheit_freezing = 32

 

fun fahrenheit_to_celsius(f):

  (f - 32) * 5/9

 

fahrenheit_to_celsius(fahrenheit_freezing)  // prints 0

In DrRacket’s interactions area, a single input line is accepted as complete as long as it’s openers and closers are balanced, and as long as it doesn’t contain : or ; outside of an opener–closer pair. A blank line terminates multi-line input. For multi-line input where the first line would otherwise parse as complete, add : or ; at the front, either on the same line or its own line.

To get a Rhombus read-eval-print loop on the command line, use racket -I rhombus. The rules for single-line and multi-line input are the same as in DrRacket’s interactions area. Use can use the ,enter command to load a module and evaluate additional expressions in the context of that module’s body.

The definition of fahrenheit_freezing could also have been written with : instead of =, like this:

def fahrenheit_freezing: 32

By convention, however, = is used for single expressions, while : is useful for multi-line definitions and blocks. A = is interchangable for : only in certain forms, like def.

A Rhombus module can export definitions to other modules using export, and it can import other modules using import. The #lang rhombus line is a kind of import already, so normally more imports are written at the top of a module, and then exports, and then the definitions.

// f2c.rhm

#lang rhombus

 

export:

  fahrenheit_freezing

  fahrenheit_to_celsius

 

def fahrenheit_freezing = 32

 

fun fahrenheit_to_celsius(f):

  (f - 32) * 5/9

// freezing.rhm

#lang rhombus

 

import:

  "f2c.rhm"

 

f2c.fahrenheit_to_celsius(f2cfahrenheit_freezing)  // prints 0

Refer to imported bindings using a prefix name and then .. The prefix is inferred from a module path by taking its last component and removing any extension, so that’s why the import of "f2c.rhm" leads to the f2c prefix. To supply an explicit prefix, use the as modifier:

import:

  "f2c.rhm" as convert

 

convert.fahrenheit_to_celsius(convert.fahrenheit_freezing)

Use the open modifier to import without a prefix—but this kind of “namespace dumping” is considered bad style in most cases:

import:

  "f2c.rhm" open

 

fahrenheit_to_celsius(fahrenheit_freezing)

Module paths for installed libraries are written with a / separator, and the last path element is the one that determines the default import prefix.

import:

  rhombus/math

 

math.pi  // prints 3.141592653589793

Technically, the use of . with an import name as a hierarchical reference is not the same as the . operator described in the next section. We stick with / for module paths to avoid overloading . further.

The default file suffix for unquoted module paths is .rhm. To reference a Racket module, use a lib path with a .rkt suffix.

import:

  lib("racket/math.rkt")

 

math.pi  // prints 3.141592653589793

There’s a lot more to the syntax of import and export for renaming, re-exporting, and so on. See the documentation of import and export for more information.

For examples in most of this guide, we will mostly not write modules explicitly. Examples will sometimes show definitions, which are meant as part of some implicit module, with interactive examples shown with a leading >  prompt and the expected result.

def fahrenheit_freezing = 32

fun fahrenheit_to_celsius(f):

  (f - 32) * 5/9

> fahrenheit_to_celsius(fahrenheit_freezing)

0