User Tools

Site Tools


at:tutorial:basic

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
at:tutorial:basic [2007/04/05 12:01] elisagat:tutorial:basic [2007/04/17 16:24] – * tvcutsem
Line 1: Line 1:
 <note> <note>
-**UNDER CONSTRUCTION!!**+**This Tutorial is still under heavy construction!!**
 </note> </note>
 ====== Functional and Imperative Programming ====== ====== Functional and Imperative Programming ======
Line 26: Line 26:
 >>[7,5] >>[7,5]
 </code> </code>
-Reference is just done by evaluating the variable. + 
 +The variable name is used to refer a variable. The variable is evaluated when referenced.  
 +<code> 
 +>x 
 +>>7 
 +</code>
  
 ===== Tables ===== ===== Tables =====
Line 44: Line 49:
 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 table whose entries are other tables. 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 table whose entries are other tables.
 <code> <code>
->def vocals := ["a", "e", "i", "o", "u"]+>def vowels := ["a", "e", "i", "o", "u"]
 >>["a", "e", "i", "o", "u"] >>["a", "e", "i", "o", "u"]
->table[3] := vocals+>table[3] := vowels
 >>[1, 2, ["a", "e", "i", "o", "u"], 4, 5] >>[1, 2, ["a", "e", "i", "o", "u"], 4, 5]
 >table[3][2] >table[3][2]
Line 52: Line 57:
 </code> </code>
  
-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 in a table.+As shown in the definition of the varible //vowels//, evaluating a series of comma-separated data types between square brackets (aka a tabulation) results in a table.
  
 <code> <code>
Line 59: Line 64:
 </code> </code>
  
-=== Table Splicing ===+==== Table Splicing ====
  
-TODO!+AmbientTalk provides the operator @ to splice tables into surrounding table expressions.  
 +<code> 
 +>[1,@[2,3],4] 
 +>>[1, 2, 3, 4] 
 +>[1, @[2,[3]], [4], @[5], @[], 6] 
 +>>[1, 2, [3], [4], 5, 6] 
 +</code> 
 + 
 +The splicing operator can be also used for matching table elements as shown below. 
 +<code> 
 +>def [first, @rest] := [1,2,3,4] 
 +>>[1, 2, 3, 4] 
 +>rest 
 +>>[2, 3, 4] 
 +</code>
  
 ===== Functions ===== ===== Functions =====
Line 108: Line 127:
 </code> </code>
  
-Variables and functions defined locally to functions are only visible in the scope of the function where there were defined.  In the previous example, //fac// uses a local function //inner// that is only visible inside //fac// and its nested scopes, in the example //fac.inner.//+This example also illustrates how a function can be made private by means of lexical scope. Variables and functions defined locally to functions are only visible in the scope of the function where there were defined. Note that local //inner// function is only visible inside the //fac// function and its nested scopes. Thuscalling //fac.inner(2,3)// will return a lookup failure error.
    
-=== Variable-Length Argument Functions ===+==== Variable-Length Argument Functions ====
  
-You can create functions that take an arbitrary  number of arguments by means of the splicing operator **@** as shown below:+You can create functions that take an arbitrary number of arguments by means of the splicing operator **@** which splices the table containing the parameters into the argument list.
 <code> <code>
 >def sum(@args){ {  >def sum(@args){ { 
Line 123: Line 142:
 </code> </code>
  
-When the //sum// function is called, the arguments are passed to the function in a table called //args// which can also be modified inside the body of the function. An alternative definition of the //sum// function follows:+When the //sum// function is called, the //args// table is spliced and passed as the argument list to the function. Note that the //args// table can also be modified inside the body of the function.  
 + 
 +Alternatively, we could define the //sum// function to take at least two numbers as shown below:
 <code> <code>
 >def sum(a, b, @rest){ {  >def sum(a, b, @rest){ { 
Line 134: Line 155:
 </code> </code>
  
-In this example the //sum// function accepts an arbitrary number of arguments as long as two arguments, //a// and //b//, are supplied. //a// and //b// are thus considered as mandatory arguments. A function can also declare optional arguments as shown below:+In that case, the //sum// function still accepts an arbitrary number of arguments as long as two arguments are supplied. //a// and //b// are considered as mandatory arguments of the argument list 
 + 
 +A function can also declare optional arguments as shown below. Optional arguments can be omitted in a function call. Internally, the default value provided in their definition is passed as the argument to the function. 
 <code> <code>
 >def incr( number, step := 1){ number + step} >def incr( number, step := 1){ number + step}
Line 143: Line 166:
 >>6 >>6
 </code> </code>
- 
  
 ===== Closures ===== ===== Closures =====
  
-The function name can also be used just to refer the function but without calling it. TODO!+As you have probably noticed in the previous examples,  the value returned by a function definition is a closure. Actually in AmbientTalk functions are implemented as named closures.  
 + 
 +The function name can be thus used to refer the function (without calling it). This will also return a closure to that function. As an example consider the //makeCell// function: 
 +<code> 
 +>def makeCell(val){ 
 +   def getter() { val} ; 
 +   def setter(v) {val := v}; 
 +  [getter, setter] 
 +
 +>><closure:makeCell> 
 +>def [get, set] := makeCell(42); 
 +>>[<closure:getter>, <closure:setter>
 +</code> 
 + 
 +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 get and set could be then passed as arguments to other functions such as //trustedFunction(get,set)// and  //distrustedFunction(get)//
  
 ===== Blocks ===== ===== Blocks =====
Line 153: Line 189:
 In AmbientTalk, blocks are merely syntactic sugar for anonymous closures (aka lambdas).  Blocks are creating using the {} braces in the form of: In AmbientTalk, blocks are merely syntactic sugar for anonymous closures (aka lambdas).  Blocks are creating using the {} braces in the form of:
 <code> <code>
-{ | <parlist> | <body>}+{ |<parlist>| <body> }
 </code> </code>
 If the block do not require any parameter, the |<parlist>| can be omitted.  Consider a basic block to sum two numbers: If the block do not require any parameter, the |<parlist>| can be omitted.  Consider a basic block to sum two numbers:
Line 162: Line 198:
 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.
 <code> <code>
->{|a, b, @rest| def total := a + b; foreach: { |el| total := total + el} in: rest; total }(1,2,3)+>{|a, b, @rest|  
 +   def total := a + b;  
 +   foreach: { |el| total := total + el} in: rest; total  
 + }(1,2,3)
 >>6 >>6
 </code> </code>
 +
 +This example also illustrates that blocks are also used to iterate over enumerations, such as in //foreach: {} in: table//.
 +
 AmbientTalk doesn’t support function assigment. However, one can assign blocks to variables. In order to call the block the name of the variable must be used. If the block defined parameters, these are required to the call as argument list. What follows is an example of such manipulation: AmbientTalk doesn’t support function assigment. However, one can assign blocks to variables. In order to call the block the name of the variable must be used. If the block defined parameters, these are required to the call as argument list. What follows is an example of such manipulation:
 <code> <code>
->def square := { |x| x * x}+>def square := { |x| x * x }
 >><closure:lambda> >><closure:lambda>
->square(1,2) +>square(3) 
->>3+>>9 
 +</code> 
 + 
 +===== Keywords ===== 
 + 
 +AmbientTalk supports keyword messages. We have already seen some examples of keyword messages in the previous sections such as the foreach structure. In AmbientTalk keywords are transformed by the parser into functions in the form: 
 +<code> 
 +def foo: arg1 bar: arg2 {...} 
 +def foo:bar:(arg1,arg2){..} 
 +</code> 
 + 
 +===== Native Data Types ===== 
 + 
 + 
 +The basic types in AmbientTalk are numbers, fractions, text, tables and booleans. In fact, 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 of the tutorial. This section explains the basic data types and includes some examples how to manipulate them. The complete list of methods can be found in the language reference. 
 + 
 +==== Numerical data types ==== 
 + 
 +AmbientTalk supports numbers and fractions which represent what other languages call integers and floating point numbers, respectively.   
 + 
 +Note that since numerical types are objects in AmbientTalk, the traditional operators +,-,*,/, >, <, <=, >=, =, !=  are nothing but syntactic sugar for method invocations. Therefore,  //1+1// is internally translated into //1.+(1)//. Unary operators are just applicationse.g. //-5// is internally translated into //-(5)//. What follows are some basic examples of manipulations with numeric types: 
 +<code> 
 +>1.inc() 
 +>>2 
 +>-1.abs(
 +>>
 +>1.cos() 
 +>>0.5403023058681398 
 +>1 ** 5 
 +>>[1, 2, 3, 4] 
 +>5 *** 1 
 +>>[5, 4, 3, 2, 1] 
 +>1.4567.round() 
 +>>1 
 +>1.8.floor() 
 +>>1 
 +>1.4.ceiling() 
 +>>2 
 +</code> 
 + 
 +Numbers also support some useful iterator methods such as: 
 +<code> 
 +>6.to: 0 step: 2 do: { |i| system.println(i) } 
 +
 +
 +
 +>>nil  
 +>3.doTimes: { |i| system.println(i) } 
 +
 +
 +
 +>>nil 
 +</code> 
 + 
 +==== Texts ==== 
 + 
 + 
 +A text data type represent a string of characters. Texts are often created using sequences of characters surrounded by double quotes ("). AmbientTalk doesn't use different notation for character or texts so a character can be created as //"a"// What follows is some basic examples of some useful native methods supported by text objects: 
 +<code> 
 +>"ambienttalk".explode() 
 +>>["a", "m", "b", "i", "e", "n", "t", "t", "a", "l", "k"
 +>"one, two, three".split(","
 +>>["one", "two", "three"
 +>"ambienttalk".replace: "[aeiou]" by: { 
 + |vowel| vowel.toUpperCase()  
 +
 +>>"AmbIEnttAlk" 
 +>"A".toLowerCase() 
 +>>"a" 
 +>"ambienttalk".length() 
 +>>11 
 +</code> 
 + 
 +AmbientTalk also provides some useful support for pattern matching using regular expressions.  
 +<code> 
 +>"ambienttalk" ~= "java" 
 +>>false 
 +>"ambienttalk" ~= ".*tt.*" 
 +>>true 
 +</code> 
 + 
 +==== 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. 
 +<code> 
 +>[1,2,3].filter: {|e| e != 2 } 
 +>>[1, 3] 
 +>[1,2,3].map: { |i| i + 1 } 
 +>>[2, 3, 4] 
 +>def vowels := ["a", "e", "i", "o", "u"
 +>>["a", "e", "i", "o", "u"
 +>vowels.length 
 +>>5 
 +>vowels.at(1) 
 +>>"a" 
 +>vowels.atPut(1, "z"
 +>>"z" 
 +>vowels 
 +>>["z", "e", "i", "o", "u"
 +>vowels.select(2,5).implode() 
 +>>"eio" 
 +>vowels.isEmpty() 
 +>>false 
 +</code> 
 + 
 +Tables also support some useful iterator methods as shown below. 
 + 
 +<code> 
 +>def sum:= 0;  
 +>>0 
 +>[1,2,3].each: { |i| sum := sum + i } 
 +>>nil 
 +>sum 
 +>>6 
 +>def sumNnum (@args) { 
 +  args.inject: 0 into: { |total, next| total + next} 
 +
 +>><closure:sumNnum> 
 +>sumNnum(1,2,3) 
 +>>6 
 +</code> 
 + 
 +==== Booleans ==== 
 +  
 + 
 +AmbientTalk supports infix operators for booleans as &, | and !. As any native type, booleans are objects so, they respond to keyword messages such as: 
 +<code> 
 +<booleanexpr>.ifTrue: { ...}  
 +<booleanexpr>.ifFalse: { ...}  
 +<booleanexpr>.ifTrue: { ...}  ifFalse: {} 
 +<booleanexpr>.whileTrue: {...} 
 +</code> 
 + 
 +**=** 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 manipulation: 
 +<code> 
 +>(0 < 1).ifTrue: { 0 }  
 +>>0 
 +>(3 != 5).ifTrue: { 1 } ifFalse: { 0 } 
 +>>1 
 +> def [i, j] := [1,3] 
 +>>>[1, 3] 
 +>{i < j}.whileTrue: { system.println(i); i := i + 1 } 
 +
 +
 +>>nil 
 +</code> 
 + 
 +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: 
 +<code> 
 +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 
 +</code> 
 +An example of usage for some of these structures is shown below in the definition of the sort function. 
 +<code> 
 +>def sort(table, cmp := { |e1,e2| e1 < e2 }) { 
 + def quickSort(table, low, high) { 
 +     def left := low; 
 +     def right := high; 
 +     def pivot := table[(left+right) /- 2]; 
 +     def save := nil; 
 +        while: { left <= right } do: { 
 +     while: { cmp(table[left], pivot) } do: {  
 +                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<right) then: { quickSort(table,low,right) }; 
 +    if: (high>left) then: { quickSort(table,left,high) }; 
 +    table; 
 +   }; 
 +   quickSort(table, 1, table.getLength()); 
 + }; 
 +>><closure:sort> 
 +>sort([2,37,6,4,5,8]) 
 +>>[2, 4, 5, 6, 8, 37]
 </code> </code>
at/tutorial/basic.txt · Last modified: 2020/02/09 22:05 by elisag