1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
// This is a comment
// 1. Basics
// Functions
func Add(X : Univ_Integer; Y : Univ_Integer) -> Univ_Integer is
return X + Y;
end func Add;
// End of line semi-colons are optional
// +, +=, -, -=, *, *=, /, /=
// all do what you'd expect (/ is integer division)
// If you find Univ_Integer to be too verbose you can import Short_Names
// which defines aliases like Int for Univ_Integer and String for Univ_String
import PSL::Short_Names::*, *
func Greetings() is
const S : String := "Hello, World!"
Println(S)
end func Greetings
// All declarations are 'const', 'var', or 'ref'
// Assignment is :=, equality checks are ==, and != is not equals
func Boolean_Examples(B : Bool) is
const And := B and #true // Parallel execution of operands
const And_Then := B and then #true // Short-Circuit
const Or := B or #false // Parallel execution of operands
const Or_Else := B or else #false // Short-Cirtuit
const Xor := B xor #true
var Result : Bool := #true;
Result and= #false;
Result or= #true;
Result xor= #false;
end func Boolean_Examples
// Booleans are a special type of enumeration
// All enumerations are preceded by a sharp '#'
func Fib(N : Int) {N >= 0} -> Int is
if N <= 1 then
return N
else
// Left and right side of '+' are computed in Parallel here
return Fib(N - 1) + Fib(N - 2)
end if
end func Fib
// '{N >= 0}' is a precondition to this function
// Preconditions are built in to the language and checked by the compiler
// ParaSail does not have mutable global variables
// Instead, use 'var' parameters
func Increment_All(var Nums : Vector<Int>) is
for each Elem of Nums concurrent loop
Elem += 1
end loop
end func Increment_All
// The 'concurrent' keyword in the loop header tells the compiler that
// iterations of the loop can happen in any order.
// It will choose the most optimal number of threads to use.
// Other options are 'forward' and 'reverse'.
func Sum_Of_Squares(N : Int) -> Int is
// The type of Sum is inferred
var Sum := 0
for I in 1 .. N forward loop
Sum += I ** 2 // ** is exponentiation
end loop
end func Sum_Of_Squares
func Sum_Of(N : Int; Map : func (Int) -> Int) -> Int is
return (for I in 1 .. N => <0> + Map(I))
end func Sum_Of
// It has functional aspects as well
// Here, we're taking an (Int) -> Int function as a parameter
// and using the inherently parallel map-reduce.
// Initial value is enclosed with angle brackets
func main(Args : Basic_Array<String>) is
Greetings() // Hello World
Println(Fib(5)) // 5
// Container Comprehension
var Vec : Vector<Int> := [for I in 0 .. 10 {I mod 2 == 0} => I ** 2]
// Vec = [0, 4, 16, 36, 64, 100]
Increment_All(Vec)
// Vec = [1, 5, 17, 37, 65, 101]
// '|' is an overloaded operator.
// It's usually used for concatenation or adding to a container
Println("First: " | Vec[1] | ", Last: " | Vec[Length(Vec)]);
// Vectors are 1 indexed, 0 indexed ZVectors are also available
Println(Sum_Of_Squares(3))
// Sum of fibs!
Println(Sum_Of(10, Fib))
end func main
// Preceding a type with 'optional' allows it to take the value 'null'
func Divide(A, B, C : Real) -> optional Real is
// Real is the floating point type
const Epsilon := 1.0e-6;
if B in -Epsilon .. Epsilon then
return null
elsif C in -Epsilon .. Epsilon then
return null
else
return A / B + A / C
end if
end func Divide
// 2. Modules
// Modules are composed of an interface and a class
// ParaSail has object orientation features
// modules can be defined as 'concurrent'
// which allows 'locked' and 'queued' parameters
concurrent interface Locked_Box<Content_Type is Assignable<>> is
// Create a box with the given content
func Create(C : optional Content_Type) -> Locked_Box;
// Put something into the box
func Put(locked var B : Locked_Box; C : Content_Type);
// Get a copy of current content
func Content(locked B : Locked_Box) -> optional Content_Type;
// Remove current content, leaving it null
func Remove(locked var B : Locked_Box) -> optional Content_Type;
// Wait until content is non-null, then return it, leaving it null.
func Get(queued var B : Locked_Box) -> Content_Type;
end interface Locked_Box;
concurrent class Locked_Box is
var Content : optional Content_Type;
exports
func Create(C : optional Content_Type) -> Locked_Box is
return (Content => C);
end func Create;
func Put(locked var B : Locked_Box; C : Content_Type) is
B.Content := C;
end func Put;
func Content(locked B : Locked_Box) -> optional Content_Type is
return B.Content;
end func Content;
func Remove(locked var B : Locked_Box) -> Result : optional Content_Type is
// '<==' is the move operator
// It moves the right operand into the left operand,
// leaving the right null.
Result <== B.Content;
end func Remove;
func Get(queued var B : Locked_Box) -> Result : Content_Type is
queued until B.Content not null then
Result <== B.Content;
end func Get;
end class Locked_Box;
func Use_Box(Seed : Univ_Integer) is
var U_Box : Locked_Box<Univ_Integer> := Create(null);
// The type of 'Ran' can be left out because
// it is inferred from the return type of Random::Start
var Ran := Random::Start(Seed);
Println("Starting 100 pico-threads trying to put something in the box");
Println(" or take something out.");
for I in 1..100 concurrent loop
if I < 30 then
Println("Getting out " | Get(U_Box));
else
Println("Putting in " | I);
U_Box.Put(I);
// The first parameter can be moved to the front with a dot
// X.Foo(Y) is equivalent to Foo(X, Y)
end if;
end loop;
Println("And the winner is: " | Remove(U_Box));
Println("And the box is now " | Content(U_Box));
end func Use_Box;
|