at:tutorial:basic
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
at:tutorial:basic [2007/04/05 14:12] – elisag | at:tutorial:basic [2007/04/17 17:25] – tvcutsem | ||
---|---|---|---|
Line 1: | Line 1: | ||
< | < | ||
- | **IN PROGRESS!!** | + | **This Tutorial is still under heavy construction!!** |
- | - TODO: Talk about methods instead of functions? Check iat chapter. | + | |
</ | </ | ||
====== Functional and Imperative Programming ====== | ====== Functional and Imperative Programming ====== | ||
- | This part of the tutorial | + | This part of the tutorial |
===== Variables ===== | ===== Variables ===== | ||
- | As usual, one can define, assign and refer to a variable. Variable definitions are made with the keyword **def**. Note that AmbientTalk is a dynamically typed language so, variables do not have a type but, they just contain | + | As usual, one can define, assign and refer to a variable. Variable definitions are made with the keyword **def**. Note that AmbientTalk is a dynamically typed language, so variables do not have a type but can contain |
- | In the examples we use the interactive AmbientTalk shell (iat) where the input and output prompt are represented by > and >> | + | In the examples we use the interactive AmbientTalk shell (iat) where the input and output prompt are represented by > and %%>>%% respectively. |
< | < | ||
Line 20: | Line 19: | ||
</ | </ | ||
- | Variable definitions can be combined with assignments as shown above. As in Pico, assignments uses the ":=" | + | Variable definitions can include an initialization expression that immediately initializes the variable. Variable assignment is performed by means of the well-known '' |
- | An assignment consists of one or more expressions, | ||
< | < | ||
>[x, y] := [ y, x ] | >[x, y] := [ y, x ] | ||
>> | >> | ||
</ | </ | ||
- | Reference | + | |
+ | As we will explain later, the '' | ||
+ | |||
+ | The variable name is used to refer a variable. The variable is evaluated when referenced. | ||
+ | < | ||
+ | >x | ||
+ | >>7 | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | When using the '': | ||
+ | </ | ||
===== Tables ===== | ===== Tables ===== | ||
- | Indexed tables represent | + | The //table// is AmbientTalk' |
< | < | ||
- | def t[ <size> ] { <expression> } | + | def t[ <sizeexpression> ] { <initexpression> } |
</ | </ | ||
- | This means that the <expression> will be evaluated | + | This constructs a table, |
< | < | ||
>def z := 0 | >def z := 0 | ||
Line 43: | Line 53: | ||
</ | </ | ||
- | Although there is no special constructor for definition of multidimensional tables, a table entry can contain another table. This is internally stored as a unidimensional | + | Although there is no special constructor for definition of multidimensional tables, a table entry can contain another table. This is internally stored as a one-dimensional |
< | < | ||
- | > | + | > |
>> | >> | ||
- | > | + | > |
>>[1, 2, [" | >>[1, 2, [" | ||
> | > | ||
Line 53: | Line 63: | ||
</ | </ | ||
- | As shown in the definition of the varible //vocals//, evaluating a series of comma-separated abstract grammar values between square brackets (aka a tabulation) results | + | As shown in the definition of the variable '' |
< | < | ||
Line 60: | Line 70: | ||
</ | </ | ||
- | === Table Splicing === | + | ==== Table Splicing |
- | TODO! | + | AmbientTalk provides the //splice operator// '' |
+ | < | ||
+ | > | ||
+ | >>[1, 2, 3, 4] | ||
+ | >[1, @[2,[3]], [4], @[5], @[], 6] | ||
+ | >>[1, 2, [3], [4], 5, 6] | ||
+ | </ | ||
+ | |||
+ | The splicing operator can be also used in the left-hand side of an assignment or definition to separate the head of a table with its rest elements, as shown below. | ||
+ | < | ||
+ | >def [first, @rest] := [1,2,3,4] | ||
+ | >>[1, 2, 3, 4] | ||
+ | >rest | ||
+ | >>[2, 3, 4] | ||
+ | </ | ||
===== Functions ===== | ===== Functions ===== | ||
- | As variables and tables, functions are defined with the keyword **def** in the form of: | + | Analogous to variables and tables, functions are defined with the keyword **def** in the form of: |
< | < | ||
def functionname( < | def functionname( < | ||
</ | </ | ||
- | The argument list is just a list of local variables which are always evaluated one by one from left to right. A basic function looks like this: | + | The argument list is just a list of local variables which are always evaluated one by one from left to right. Hence, AmbientTalk employs // |
< | < | ||
>def square (x) { x*x } | >def square (x) { x*x } | ||
Line 77: | Line 101: | ||
>>25 | >>25 | ||
</ | </ | ||
- | This example also illustrates | + | This example also illustrates |
< | < | ||
- | >def f(){nil} | + | >def f() { nil } |
>>< | >>< | ||
>f() | >f() | ||
>>nil | >>nil | ||
</ | </ | ||
- | The return value of a function is the result of the last statement | + | The return value of a function is the result of the last executed |
- | Functions have access | + | < |
+ | A function definition is a statement. The body of a function can contain a list of statements, each separated by '';'' | ||
+ | < | ||
+ | def funA() { | ||
+ | // do something useful | ||
+ | } | ||
+ | def funB() { | ||
+ | // do something else | ||
+ | } | ||
+ | </ | ||
+ | The parser will complain saying that '' | ||
+ | </ | ||
+ | |||
+ | Functions in AmbientTalk are //lexically scoped//, which means that free variables are looked up in the enclosing environment of the function | ||
< | < | ||
>def counter := 0 | >def counter := 0 | ||
Line 100: | Line 137: | ||
>def fac(n) { | >def fac(n) { | ||
def inner(n, result) { | def inner(n, result) { | ||
- | if: (n =0) then: { result } else: { inner( n-1, n * result) | + | if: (n = 0) then: { result } else: { inner( n-1, n * result) |
}; | }; | ||
inner(n,1) | inner(n,1) | ||
Line 109: | Line 146: | ||
</ | </ | ||
- | Variables and functions defined locally to functions are only visible in the scope of the function where there were defined. | + | This example also illustrates how a function can be made " |
- | === Variable-Length Argument Functions === | ||
- | You can create functions that take an arbitrary | + | ==== Variable-Length Argument Functions ==== |
+ | |||
+ | You can create functions that take an arbitrary number of arguments | ||
< | < | ||
- | >def sum(@args){ { | + | >def sum(@args) { |
def total := 0; | def total := 0; | ||
foreach: { |el| total := total + el } in: args; | foreach: { |el| total := total + el } in: args; | ||
- | total} | + | total |
+ | }; | ||
>>< | >>< | ||
> | > | ||
Line 124: | Line 163: | ||
</ | </ | ||
- | When the //sum// function is called, the arguments are passed to the function | + | When the //sum// function is called, the //args// table is spliced and passed |
+ | |||
+ | Alternatively, | ||
< | < | ||
>def sum(a, b, @rest){ { | >def sum(a, b, @rest){ { | ||
Line 135: | Line 176: | ||
</ | </ | ||
- | In this example | + | In that case, the //sum// function |
+ | |||
+ | A function can also declare optional arguments as shown below. Optional arguments can be omitted in a function call. If this is the case, the default expression provided in their definition is evaluated and passed as argument to the function instead. | ||
< | < | ||
>def incr( number, step := 1){ number + step} | >def incr( number, step := 1){ number + step} | ||
Line 145: | Line 188: | ||
</ | </ | ||
+ | As is customary in languages with the above parameter passing semantics, AmbientTalk requires mandatory parameters to be defined //before// optional parameters, which should in turn be defined //before// a variable-argument parameter, if any. | ||
===== Closures ===== | ===== Closures ===== | ||
- | The function name can also be used just to refer the function | + | As you have probably noticed in the previous examples, |
+ | |||
+ | The function name can be thus used to refer the function | ||
+ | < | ||
+ | >def makeCell(val){ | ||
+ | def getter() { val} ; | ||
+ | def setter(v) {val := v}; | ||
+ | [getter, setter] | ||
+ | } | ||
+ | >>< | ||
+ | >def [get, set] := makeCell(42); | ||
+ | >> | ||
+ | </ | ||
+ | |||
+ | This example also illustrates how a function can make public some of its local fields or functions by returning them as its return value. The '' | ||
===== Blocks ===== | ===== Blocks ===== | ||
- | In AmbientTalk, | + | In AmbientTalk, |
< | < | ||
{ |< | { |< | ||
</ | </ | ||
- | If the block do not require any parameter, the |< | + | |
+ | If the block does not require any parameter, the |< | ||
< | < | ||
- | >{| a, b| a+ b} (3,2) | + | >{|a, b| a+ b}(3,2) |
>>5 | >>5 | ||
</ | </ | ||
Note that the argument list passed to the block can define the different types of arguments previously explained. | Note that the argument list passed to the block can define the different types of arguments previously explained. | ||
< | < | ||
- | >{|a, b, @rest| | + | >def sum := {|a, b, @rest| |
def total := a + b; | def total := a + b; | ||
| | ||
- | | + | }; sum(1,2,3) |
>>6 | >>6 | ||
</ | </ | ||
- | AmbientTalk | + | |
+ | This example also illustrates that blocks are also used to iterate over enumerations, | ||
+ | |||
+ | < | ||
+ | AmbientTalk | ||
+ | </ | ||
+ | |||
+ | ===== Keywords ===== | ||
+ | |||
+ | AmbientTalk supports keyworded messages, as in Smalltalk and Self. We have already seen some examples of keyword messages in the previous sections such as the '' | ||
+ | |||
+ | < | ||
+ | >def map: clo onto: tbl { | ||
+ | def i := 0; | ||
+ | def mapped[tbl.length] { | ||
+ | clo(tbl[i: | ||
+ | }; | ||
+ | } | ||
+ | >> < | ||
+ | </ | ||
+ | |||
+ | It can be invoked as follows: | ||
+ | < | ||
+ | >map: square onto: [1,2,3] | ||
+ | >> | ||
+ | </ | ||
+ | |||
+ | In AmbientTalk keyworded functions and function calls are actually syntactic sugar. They are transformed by the parser into their canonical equivalent. Hence: | ||
+ | < | ||
+ | def foo: arg1 bar: arg2 {...} | ||
+ | </ | ||
+ | is transformed into: | ||
+ | < | ||
+ | def foo: | ||
+ | </ | ||
+ | |||
+ | However, it is impossible | ||
+ | |||
+ | ===== Native Data Types ===== | ||
+ | |||
+ | The basic data types in AmbientTalk are numbers (i.e. integers), fractions (i.e. double precision floating point numbers), text (i.e. strings), tables (i.e. arrays) and booleans. In fact, instances of these data types are nothing but objects and as such, they respond to a variety of native methods. Objects will be the subject of the next chapter | ||
+ | |||
+ | ==== Numerical data types ==== | ||
+ | |||
+ | AmbientTalk supports numbers and fractions which represent what other languages call integers and double precision floating point numbers, respectively. | ||
+ | |||
+ | Note that since numerical types are objects in AmbientTalk, | ||
+ | < | ||
+ | > | ||
+ | >>2 | ||
+ | > | ||
+ | >> | ||
+ | >1 ** 5 | ||
+ | >>[1, 2, 3, 4] | ||
+ | >5 *** 1 | ||
+ | >>[5, 4, 3, 2, 1] | ||
+ | > | ||
+ | >>1 | ||
+ | > | ||
+ | >>1 | ||
+ | > | ||
+ | >>2 | ||
+ | </ | ||
+ | |||
+ | Beware of the precedence rules for function application versus method invocation, which may lead to unexpected results, e.g.: | ||
+ | </ | ||
+ | > | ||
+ | >> | ||
+ | < | ||
+ | This code is interpreted as '' | ||
+ | |||
+ | Numbers also support some useful iterator methods such as: | ||
+ | < | ||
+ | >6.to: 0 step: 2 do: { |i| system.println(i) } | ||
+ | 6 | ||
+ | 4 | ||
+ | 2 | ||
+ | >>nil | ||
+ | > | ||
+ | 1 | ||
+ | 2 | ||
+ | 3 | ||
+ | >> | ||
+ | </ | ||
+ | |||
+ | ==== Texts ==== | ||
+ | |||
+ | |||
+ | A text data type represent a string of characters. Texts are often created using sequences of characters surrounded by double quotes ("). AmbientTalk doesn' | ||
+ | < | ||
+ | >" | ||
+ | >> | ||
+ | >" | ||
+ | >> | ||
+ | >" | ||
+ | | ||
+ | } | ||
+ | >>" | ||
+ | >" | ||
+ | >>" | ||
+ | >" | ||
+ | >> | ||
+ | </ | ||
+ | |||
+ | AmbientTalk also provides some useful support for pattern matching using regular expressions. | ||
+ | < | ||
+ | >" | ||
+ | >> | ||
+ | >" | ||
+ | >> | ||
+ | </ | ||
+ | |||
+ | ==== Tables ==== | ||
+ | |||
+ | |||
+ | We have already introduce how to define tables. Let us now focus on how to manipulate them with the native methods provided by the table object. | ||
+ | < | ||
+ | > | ||
+ | >>[1, 3] | ||
+ | > | ||
+ | >>[2, 3, 4] | ||
+ | >def vowels := [" | ||
+ | >> | ||
+ | > | ||
+ | >>5 | ||
+ | > | ||
+ | >>" | ||
+ | > | ||
+ | >>" | ||
+ | > | ||
+ | >> | ||
+ | > | ||
+ | >>" | ||
+ | > | ||
+ | >> | ||
+ | </ | ||
+ | |||
+ | Tables also support some useful iterator methods as shown below. | ||
+ | |||
+ | < | ||
+ | >def sum:= 0; | ||
+ | >>0 | ||
+ | > | ||
+ | >> | ||
+ | >sum | ||
+ | >>6 | ||
+ | >def sumNnum (@args) { | ||
+ | args.inject: | ||
+ | } | ||
+ | >>< | ||
+ | > | ||
+ | >>6 | ||
+ | </ | ||
+ | |||
+ | ==== Booleans ==== | ||
+ | |||
+ | |||
+ | AmbientTalk supports infix operators for booleans as &, | and !. As any native type, booleans are objects so, they respond to keyword messages | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | **=** and **!=** are the infix operators for equality and inequality. **true** and **false** are the boolean constant objects. What follows is some basic examples of boolean | ||
+ | < | ||
+ | >(0 < 1).ifTrue: { 0 } | ||
+ | >>0 | ||
+ | >(3 != 5).ifTrue: { 1 } ifFalse: { 0 } | ||
+ | >>1 | ||
+ | > def [i, j] := [1,3] | ||
+ | >>> | ||
+ | >{i < j}.whileTrue: | ||
+ | 1 | ||
+ | 2 | ||
+ | >> | ||
+ | </ | ||
+ | |||
+ | Boolean infix operators such as & and | are not shortcut. Thus, both arguments will be evaluated. For lazy evaluation, you should use the natives methods. For example, false.and: { 1/0 } will return false without executing the second argument. | ||
+ | |||
+ | ===== Control Flow Structures ===== | ||
+ | |||
+ | Control flow structures are defined in the lexical root of AmbientTalk. The lexical root is an object containing globally visible native methods. We have already seen in the previous sections examples of usage of the foreach and if/then structures. The complete list of traditional control flow structures defined in AmbientTalk is shown below: | ||
+ | < | ||
+ | if: booleanCondition then: { consequent } | ||
+ | if: booleanCondition then: { consequent } else: { alternative } | ||
+ | while: { condition } do: { body } | ||
+ | foreach: { |v| body } in: [ table ] | ||
+ | do: { body } if: condition | ||
+ | do: { body } unless: condition | ||
+ | </ | ||
+ | An example of usage for some of these structures is shown below in the definition of the sort function. | ||
< | < | ||
- | > | + | > |
- | >>< | + | def quickSort(table, |
- | >square(1,2) | + | def left := low; |
- | >>3 | + | def right := high; |
+ | def pivot := table[(left+right) /- 2]; | ||
+ | def save := nil; | ||
+ | while: { left <= right } do: { | ||
+ | while: { cmp(table[left], | ||
+ | left := left + 1 | ||
+ | }; | ||
+ | while: { cmp(pivot, table[right]) } do: { | ||
+ | right := right - 1 | ||
+ | }; | ||
+ | if: (left <= right) then: { | ||
+ | // swap elements | ||
+ | save := table[left]; | ||
+ | table[left] := table[right]; | ||
+ | table[right] := save; | ||
+ | left := left + 1; | ||
+ | right := right - 1; | ||
+ | }; | ||
+ | }; | ||
+ | if: (low< | ||
+ | if: (high> | ||
+ | | ||
+ | }; | ||
+ | quickSort(table, | ||
+ | }; | ||
+ | >>< | ||
+ | >sort([2, | ||
+ | >>[2, 4, 5, 6, 8, 37] | ||
</ | </ |
at/tutorial/basic.txt · Last modified: 2020/02/09 22:05 by elisag