Previous Up Next

Chapter 1  A tutorial introduction

Let us begin with a quick introduction to the syntax and major features of the Moby programming language.

1.1  Getting started

Following tradition, our first program is the infamous ``hello world'' example. In Moby, one implementation is as follows:
module Main {
  val () = ConsoleIO.print "hello world\n"
}
The code in this figure constitutes a compilation unit. All Moby programs are constructed from a collection of compilation units. This program consists of the module Main, which contains an empty binding with a right-hand-side consisting of the application of the print function from the ConsoleIO module to the string literal "hello world\n". The ConsoleIO module is part of the Moby basis and provides support for input and output to the console device associated with the program.
describe how to compile and run this program?

1.2  Values and expressions

Moby is primarily a value oriented language --- most computation is expressed in terms of computing new values from existing ones. Expressions in Moby evaluate to a tuple of zero or more results.

Our next example is a program that computes and prints the first ten numbers in the Fibonacci sequence (a favorite of functional programmers):
module Fib {
  fun fib : Int -> Int {
    0 => 1,
    1 => 1,
    n => fib(n-1) + fib(n-2)
  }

  const N : Int = 10

  fun loop : Int -> () {
    N => (),
    i => {
      ConsoleIO.print(Int.toString(fib(i)) + "\n");
      loop (i+1)
    }
  }

  val () = loop 0

}
This example illustrates a number of Moby features. First, the definition of the fib function uses the ``definition by cases'' syntax, where the body of the function is given as a match. Following the definition of the fib function is a constant declaration, which binds the value 10 to the symbolic name N. Symbolic constants (including datatype constructors) in Moby always start with an upper-case character, while variables start with a lower-case character. This convention allows the compiler to distinguish between constants and variables in patterns. NB. the Int module is pervasive.
module Fact {
// compute the factorial function
  fun fact (n : Int) -> Int {
    if (n == 0then 1 else n*fact(n-1)
  }

// get a positive integer value from the console
  fun getInt () -> Int {
    ConsoleIO.print ("please enter a positive integer: ");
    val input = Console.inputLn ();
    case Int.fromString input of {
      (SOME x) when (x >= 0=> x,
      _ => {
        Console.print ("That isn't a positive integer!\n");
        getInt ()
      }
    }
  }

// the factorial server
  fun server () -> () {
    val n = getInt ();
    val factN = fact (n);
    ConsoleIO.print("The factorial of " + Int.toString n +
      " is " + Int.toString factN + "\n");
    server ()  // do it again!
  }

}

Previous Up Next