# Interactive NESL Tutorial

## Directions

This is an interactive tutorial for the NESL interface. At each code box you can Submit the code in the box to the NESL interpreter, and use your browser's Back button to get back to this page. To try out different things you can also modify the code in the boxes before sending it.

## Scalar Expressions

### Scalar Types and Simple Arithmetic Operations

NESL supports simple arithmetic expressions on scalar values. Scalar values include integers, floating-point numbers, booleans, and characters. You can try some of the following:
Booleans are denoted with ` t` and ` f`.
Characters are denoted using a back-quote followed by the character.

### Local Binding (`let`) and Conditional Expressions (`if`)

Local binding can be made with a `let` expression. In the following example, the variable `a` is locally bound to the result of the expression `3*4` and then used in the expression `a+(a*1)`:
Multiple assignments are allowed in a `let` expression. They must be separated by semicolons.
Conditional expressions use the syntax
```  if cond-exp then true-exp else false-exp
```
For example:

### Defining Functions

Functions are defined using the following syntax:
```  function fun-name(fun-args) = exp;
```
for example:

### Pairs and Pattern Matching

Pairs are a way to pass around multiple values in NESL. A pair is denoted by to values separated by a comma. For example:
This can be used to return multiple values from a function, and pattern matching can be done.

## Parallel Expressions

Parallelism on sequences can be achieved in two ways: the ability to apply any function concurrently over each element of a sequence, and a set of built-in parallel functions that operate on sequences.

### Sequences

NESL supports parallelism through operations on sequences. A sequence is an ordered set and is specified in NESL using square brackets. For example
` [2, 1, 9, -3] . `
Characters sequences can be written shorthand between double quotes

` "this is a sequence of characters" `
An elements of a sequence can be of any type including other sequence
` ["a","nested","sequence"] `
or pairs
` [("big",3),("brown",5),("cow",3)] `
but the elements of a given sequence must be of the same type. For example, try

### The Parallel Apply-to-each

Any function can be applied over the elements of a sequence in parallel. This is expressed using a set-like notation similar to set-formers in SETL and list-comprehensions in Miranda and Haskell. For example,
This construct can be read as: in parallel for each `x` in the sequence `[1.0,3.0,9.0]`, take the square root of `x`. Any function including user defined functions can be applied over the elements of a sequence:
The apply-to-each form can also be used to subselect elements based on a predicate, for example:
It can also be nested:

### Parallel Sequence Operations

There are many built in sequence operations in NESL. Here is a list of some of them:
```   #a          -- the length of a sequence a
a[i]        -- get the ith element of a
a ++ b      -- append a and b
take(a,n)   -- take the first n elements of a
[s,e]       -- generate a sequence of integers from s to e
sum(a)      -- sum the elements of a sequence
sort(a)     -- sort the elements of a sequence
```
Feel free to try some of them. You can type multiple expressions after the variable definitions and use the variables.

The description of any of the sequence functions (in fact, any function) can be found by using the expression
`describe funcname`
You might try finding the description of one of following functions:
```   zip, scan, min_val, max_val, any, all, count, permute,
rotate, reverse, subseq, drop, odd_elts, even_elts,
partition, flatten, collect, kth_smallest, find,
union, intersection, remove_duplicates, ....
```