/
ghul-pipes-examples.ghul
163 lines (120 loc) · 5.59 KB
/
ghul-pipes-examples.ghul
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
// make a type available in this scope without qualification
use Collections.Iterable;
// and a static method:
use IO.Std.write_line;
entry() is
// ghūl has anonymous functions:
let f = (i: int) -> string => "i is " + i;
write_line("f(123) = " + f(123));
// anonymous functions infer their return type, if it is not explicit:
let g = (j: int) => "j is " + j;
write_line("g(456) = " + g(456));
// anonymous functions can have a block body:
let h = (k: int) is
let result = "k is ";
result = result + k;
return result;
si;
write_line("h(789) = " + h(789));
// anonymous functions can capture values from outer lexical scopes -
// in this case the anonymous functions f, g and h are captured:
let closure = (i: int, j: int, k: int) => f(i) + ", " + g(j) + ", " + h(k);
write_line("captured values: " + closure(111, 222, 333));
// anonymous functions can be nested, and their frames live on after they return:
let outer = () is
let message = "hello";
let middle = () is
let inner = () => message;
return inner;
si;
return middle;
si;
let hello_inner_from_outer = outer()()();
write_line("call inner() returned by outer(): " + hello_inner_from_outer);
// '[' and ']' construct an immutable list (Collections.List[T], where T is inferred from the element type):
let list = [1, 2, 3, 4, 5, 6];
write_line("list: " + list |);
// '..' constructs an iterable integer range, inclusive of the first element and exclusive of the last:
let exclusive_range = 0..10;
write_line("exclusive int range: " + exclusive_range |);
// '::' constructs an iterable integer range, inclusive of the first and last elements:
let inclusive_range = 1::10;
write_line("inclusive int range: " + inclusive_range |);
// the '|' postfix operator converts a Collections.Iterable[T] into a Pipes.Pipe`1[T]
// Pipe`1[T] provides a number of ways to manipulate a sequence of elements
// filter passes only those elements that meet a supplied filter condition.Collections
let even = (1::8) | .filter(i => is_even(i));
write_line("even numbers: " + even);
// you generally don't need explicit argument types for anonymous functions when they're
// passed as arguments, as their types can be inferred from context:
let odd = [1, 2, 3, 4, 5, 6, 7, 8] | .filter(i => is_odd(i));
write_line("odd numbers: " + odd);
// map transforms elements according to a supplied function:
let times_3 = [1, 2, 3, 4, 5, 6, 7, 8] | .map(i => i * 3);
write_line("times 3: " + times_3);
// if you hover the mouse over the call to map, you'll see the full inferred method signature:
let strings = (1..9) | .map(i => "'" + i + "'");
write_line("map to strings: " + strings);
let strings_with_lengths =
["one", "two", "three", "four", "horse", "weevil", "six"] |
.map(s => (s, s.length));
write_line("strings with lengths: " + strings_with_lengths);
// pipes are iterable, so you can loop over them with 'for':
for iv in [1, 2, 3] | .map(i => i * 3).index() do
write_line("result #" + (iv.index + 1) + " is " + iv.value);
od
// strings are iterable:
let upper = "hello world" | .map(c => char.to_upper(c));
write_line("upper cased: " + upper | .to_string(""));
// reduce accumulates a running value according to a supplied function:
let sum = [1, 2, 3, 4, 5, 6, 7, 8] | .reduce(0, (r, e) => r + e);
write_line("sum is: " + sum);
// you can chain multiple calls in a fluent style:
let count_greater_than_3 =
[1, 2, 3, 4, 5, 6, 7, 8] |
.filter(i => i > 3)
.count();
write_line("count of elements > 3 is: " + count_greater_than_3);
let sum_double_odd =
[1, 2, 3, 4, 5, 6, 7, 8] |
.filter(i => is_odd(i))
.map(i => i * 2)
.reduce(0, (r, e) => r + e);
write_line("sum of doubled odd numbers is: " + sum_double_odd);
let first_3 = [1, 2, 3, 4, 5, 6, 7, 8] | .take(3);
write_line("take first 3: " + first_3);
let skip_3 = [1, 2, 3, 4, 5, 6, 7, 8] | .skip(3);
write_line("skip first 3: " + skip_3);
let three_from_middle =
[1, 2, 3, 4, 5, 6, 7, 8] |
.skip(3)
.take(3);
write_line("take 3 from the middle: " + three_from_middle);
let sum_three_from_middle =
[1, 2, 3, 4, 5, 6, 7, 8] |
.skip(3)
.take(3)
.reduce(0, (r, e) => r + e);
write_line("sum of 3 from the middle: " + sum_three_from_middle);
// zip combines two sequences into a single sequence of pairs/2-tuples
let zip =
[1, 2, 3, 4, 5, 6, 7, 8] |
.zip([8, 7, 6, 5, 4, 3, 2, 1]);
write_line("zip of two sequences is: " + zip);
// or into a sequence where each element is derived by passing the
// left + right elements to a supplied function:
let zip_map =
[1, 2, 3, 4, 5, 6, 7, 8] |
.zip([8, 7, 6, 5, 4, 3, 2, 1], (l, r) => l + r);
write_line("sum of zipped is: " + zip_map);
// cat concatenates two pipes into a single sequence
let cat =
[1, 2, 3, 4, 5, 6, 7, 8] |
.cat([8, 7, 6, 5, 4, 3, 2, 1]);
write_line("concatenated is: " + cat);
// .index() tags each element with its 0-based index in the sequence:
let indexed = ["cat", "dog", "fish", "zebra", "ameoba"] | .index();
write_line("indexed: " + indexed);
si
is_odd(i: int) -> bool => i ∩ 1 != 0;
is_even(i: int) -> bool => i ∩ 1 == 0;