Skip to content

Commit f1f1293

Browse files
authored
Merge branch 'master' into master
2 parents c6d9618 + be6c86d commit f1f1293

28 files changed

+3322
-863
lines changed

examples/gno.land/p/moul/fp/fp.gno

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
// Package fp provides functional programming utilities for Gno, enabling
2+
// transformations, filtering, and other operations on slices of interface{}.
3+
//
4+
// Example of chaining operations:
5+
//
6+
// numbers := []interface{}{1, 2, 3, 4, 5, 6}
7+
//
8+
// // Define predicates, mappers and reducers
9+
// isEven := func(v interface{}) bool { return v.(int)%2 == 0 }
10+
// double := func(v interface{}) interface{} { return v.(int) * 2 }
11+
// sum := func(a, b interface{}) interface{} { return a.(int) + b.(int) }
12+
//
13+
// // Chain operations: filter even numbers, double them, then sum
14+
// evenNums := Filter(numbers, isEven) // [2, 4, 6]
15+
// doubled := Map(evenNums, double) // [4, 8, 12]
16+
// result := Reduce(doubled, sum, 0) // 24
17+
//
18+
// // Alternative: group by even/odd, then get even numbers
19+
// byMod2 := func(v interface{}) interface{} { return v.(int) % 2 }
20+
// grouped := GroupBy(numbers, byMod2) // {0: [2,4,6], 1: [1,3,5]}
21+
// evens := grouped[0] // [2,4,6]
22+
package fp
23+
24+
// Mapper is a function type that maps an element to another element.
25+
type Mapper func(interface{}) interface{}
26+
27+
// Predicate is a function type that evaluates a condition on an element.
28+
type Predicate func(interface{}) bool
29+
30+
// Reducer is a function type that reduces two elements to a single value.
31+
type Reducer func(interface{}, interface{}) interface{}
32+
33+
// Filter filters elements from the slice that satisfy the given predicate.
34+
//
35+
// Example:
36+
//
37+
// numbers := []interface{}{-1, 0, 1, 2}
38+
// isPositive := func(v interface{}) bool { return v.(int) > 0 }
39+
// result := Filter(numbers, isPositive) // [1, 2]
40+
func Filter(values []interface{}, fn Predicate) []interface{} {
41+
result := []interface{}{}
42+
for _, v := range values {
43+
if fn(v) {
44+
result = append(result, v)
45+
}
46+
}
47+
return result
48+
}
49+
50+
// Map applies a function to each element in the slice.
51+
//
52+
// Example:
53+
//
54+
// numbers := []interface{}{1, 2, 3}
55+
// toString := func(v interface{}) interface{} { return fmt.Sprintf("%d", v) }
56+
// result := Map(numbers, toString) // ["1", "2", "3"]
57+
func Map(values []interface{}, fn Mapper) []interface{} {
58+
result := make([]interface{}, len(values))
59+
for i, v := range values {
60+
result[i] = fn(v)
61+
}
62+
return result
63+
}
64+
65+
// Reduce reduces a slice to a single value by applying a function.
66+
//
67+
// Example:
68+
//
69+
// numbers := []interface{}{1, 2, 3, 4}
70+
// sum := func(a, b interface{}) interface{} { return a.(int) + b.(int) }
71+
// result := Reduce(numbers, sum, 0) // 10
72+
func Reduce(values []interface{}, fn Reducer, initial interface{}) interface{} {
73+
acc := initial
74+
for _, v := range values {
75+
acc = fn(acc, v)
76+
}
77+
return acc
78+
}
79+
80+
// FlatMap maps each element to a collection and flattens the results.
81+
//
82+
// Example:
83+
//
84+
// words := []interface{}{"hello", "world"}
85+
// split := func(v interface{}) interface{} {
86+
// chars := []interface{}{}
87+
// for _, c := range v.(string) {
88+
// chars = append(chars, string(c))
89+
// }
90+
// return chars
91+
// }
92+
// result := FlatMap(words, split) // ["h","e","l","l","o","w","o","r","l","d"]
93+
func FlatMap(values []interface{}, fn Mapper) []interface{} {
94+
result := []interface{}{}
95+
for _, v := range values {
96+
inner := fn(v).([]interface{})
97+
result = append(result, inner...)
98+
}
99+
return result
100+
}
101+
102+
// All returns true if all elements satisfy the predicate.
103+
//
104+
// Example:
105+
//
106+
// numbers := []interface{}{2, 4, 6, 8}
107+
// isEven := func(v interface{}) bool { return v.(int)%2 == 0 }
108+
// result := All(numbers, isEven) // true
109+
func All(values []interface{}, fn Predicate) bool {
110+
for _, v := range values {
111+
if !fn(v) {
112+
return false
113+
}
114+
}
115+
return true
116+
}
117+
118+
// Any returns true if at least one element satisfies the predicate.
119+
//
120+
// Example:
121+
//
122+
// numbers := []interface{}{1, 3, 4, 7}
123+
// isEven := func(v interface{}) bool { return v.(int)%2 == 0 }
124+
// result := Any(numbers, isEven) // true (4 is even)
125+
func Any(values []interface{}, fn Predicate) bool {
126+
for _, v := range values {
127+
if fn(v) {
128+
return true
129+
}
130+
}
131+
return false
132+
}
133+
134+
// None returns true if no elements satisfy the predicate.
135+
//
136+
// Example:
137+
//
138+
// numbers := []interface{}{1, 3, 5, 7}
139+
// isEven := func(v interface{}) bool { return v.(int)%2 == 0 }
140+
// result := None(numbers, isEven) // true (no even numbers)
141+
func None(values []interface{}, fn Predicate) bool {
142+
for _, v := range values {
143+
if fn(v) {
144+
return false
145+
}
146+
}
147+
return true
148+
}
149+
150+
// Chunk splits a slice into chunks of the given size.
151+
//
152+
// Example:
153+
//
154+
// numbers := []interface{}{1, 2, 3, 4, 5}
155+
// result := Chunk(numbers, 2) // [[1,2], [3,4], [5]]
156+
func Chunk(values []interface{}, size int) [][]interface{} {
157+
if size <= 0 {
158+
return nil
159+
}
160+
var chunks [][]interface{}
161+
for i := 0; i < len(values); i += size {
162+
end := i + size
163+
if end > len(values) {
164+
end = len(values)
165+
}
166+
chunks = append(chunks, values[i:end])
167+
}
168+
return chunks
169+
}
170+
171+
// Find returns the first element that satisfies the predicate and a boolean indicating if an element was found.
172+
//
173+
// Example:
174+
//
175+
// numbers := []interface{}{1, 2, 3, 4}
176+
// isEven := func(v interface{}) bool { return v.(int)%2 == 0 }
177+
// result, found := Find(numbers, isEven) // 2, true
178+
func Find(values []interface{}, fn Predicate) (interface{}, bool) {
179+
for _, v := range values {
180+
if fn(v) {
181+
return v, true
182+
}
183+
}
184+
return nil, false
185+
}
186+
187+
// Reverse reverses the order of elements in a slice.
188+
//
189+
// Example:
190+
//
191+
// numbers := []interface{}{1, 2, 3}
192+
// result := Reverse(numbers) // [3, 2, 1]
193+
func Reverse(values []interface{}) []interface{} {
194+
result := make([]interface{}, len(values))
195+
for i, v := range values {
196+
result[len(values)-1-i] = v
197+
}
198+
return result
199+
}
200+
201+
// Zip combines two slices into a slice of pairs. If the slices have different lengths,
202+
// extra elements from the longer slice are ignored.
203+
//
204+
// Example:
205+
//
206+
// a := []interface{}{1, 2, 3}
207+
// b := []interface{}{"a", "b", "c"}
208+
// result := Zip(a, b) // [[1,"a"], [2,"b"], [3,"c"]]
209+
func Zip(a, b []interface{}) [][2]interface{} {
210+
length := min(len(a), len(b))
211+
result := make([][2]interface{}, length)
212+
for i := 0; i < length; i++ {
213+
result[i] = [2]interface{}{a[i], b[i]}
214+
}
215+
return result
216+
}
217+
218+
// Unzip splits a slice of pairs into two separate slices.
219+
//
220+
// Example:
221+
//
222+
// pairs := [][2]interface{}{{1,"a"}, {2,"b"}, {3,"c"}}
223+
// numbers, letters := Unzip(pairs) // [1,2,3], ["a","b","c"]
224+
func Unzip(pairs [][2]interface{}) ([]interface{}, []interface{}) {
225+
a := make([]interface{}, len(pairs))
226+
b := make([]interface{}, len(pairs))
227+
for i, pair := range pairs {
228+
a[i] = pair[0]
229+
b[i] = pair[1]
230+
}
231+
return a, b
232+
}
233+
234+
// GroupBy groups elements based on a key returned by a Mapper.
235+
//
236+
// Example:
237+
//
238+
// numbers := []interface{}{1, 2, 3, 4, 5, 6}
239+
// byMod3 := func(v interface{}) interface{} { return v.(int) % 3 }
240+
// result := GroupBy(numbers, byMod3) // {0: [3,6], 1: [1,4], 2: [2,5]}
241+
func GroupBy(values []interface{}, fn Mapper) map[interface{}][]interface{} {
242+
result := make(map[interface{}][]interface{})
243+
for _, v := range values {
244+
key := fn(v)
245+
result[key] = append(result[key], v)
246+
}
247+
return result
248+
}
249+
250+
// Flatten flattens a slice of slices into a single slice.
251+
//
252+
// Example:
253+
//
254+
// nested := [][]interface{}{{1,2}, {3,4}, {5}}
255+
// result := Flatten(nested) // [1,2,3,4,5]
256+
func Flatten(values [][]interface{}) []interface{} {
257+
result := []interface{}{}
258+
for _, v := range values {
259+
result = append(result, v...)
260+
}
261+
return result
262+
}
263+
264+
// Helper functions
265+
func min(a, b int) int {
266+
if a < b {
267+
return a
268+
}
269+
return b
270+
}

0 commit comments

Comments
 (0)