/
FunctionSyntaxTest.kt
225 lines (184 loc) · 6.51 KB
/
FunctionSyntaxTest.kt
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
package arrow.syntax.test
import arrow.syntax.function.andThen
import arrow.syntax.function.bind
import arrow.syntax.function.complement
import arrow.syntax.function.compose
import arrow.syntax.function.curried
import arrow.syntax.function.forwardCompose
import arrow.syntax.function.invoke
import arrow.syntax.function.memoize
import arrow.syntax.function.paired
import arrow.syntax.function.partially1
import arrow.syntax.function.partially2
import arrow.syntax.function.partially3
import arrow.syntax.function.partially4
import arrow.syntax.function.partially5
import arrow.syntax.function.reverse
import arrow.syntax.function.tripled
import arrow.syntax.function.tupled
import arrow.syntax.function.uncurried
import arrow.syntax.function.unpaired
import arrow.syntax.function.untripled
import arrow.syntax.function.untupled
import arrow.core.Tuple2
import arrow.core.test.UnitSpec
import io.kotlintest.shouldBe
import java.util.Random
class FunctionSyntaxTest : UnitSpec() {
val f = { prefix: String, numericPostfix: Int, values: List<String> ->
values.map { "$prefix$it$numericPostfix" }
}
private val sum = { i1: Int, i2: Int -> i1 + i2 }
private val add5 = { i: Int -> i + 5 }
private val multiplyBy2 = { i: Int -> i * 2 }
init {
"complement" {
val isEven = { x: Int -> x % 2 == 0 }
isEven(2) shouldBe true
val notEven = isEven.complement()
notEven(2) shouldBe false
}
"it should compose function correctly (andThen)" {
val potato = "potato"
val ninja = "ninja"
val get = { potato }
val map = { word: String -> ninja + word }
(get andThen map)()
(ninja + potato) shouldBe (get andThen map)()
}
"it should compose function correctly (forwardCompose)" {
val randomDigit = Random().nextInt()
val get = { randomDigit }
val pow = { i: Int -> i * i }
randomDigit * randomDigit shouldBe (get forwardCompose pow)()
}
"testAndThen" {
val add5andMultiplyBy2 = add5 andThen multiplyBy2
add5andMultiplyBy2(2) shouldBe 14
}
"testAndThen2" {
val sumAndMultiplyBy2 = sum andThen multiplyBy2
sumAndMultiplyBy2(5, 2) shouldBe 14
}
"testForwardCompose" {
val add5andMultiplyBy2 = add5 forwardCompose multiplyBy2
add5andMultiplyBy2(2) shouldBe 14
}
"testForwardCompose2" {
val sumAndMultiplyBy2 = sum forwardCompose multiplyBy2
sumAndMultiplyBy2(5, 2) shouldBe 14
}
"testCompose" {
val multiplyBy2andAdd5 = add5 compose multiplyBy2
multiplyBy2andAdd5(2) shouldBe 9
}
"testCurrying" {
val sum2ints = { x: Int, y: Int -> x + y }
val curried = sum2ints.curried()
curried(2)(4) shouldBe 6
val add5 = curried(5)
add5(7) shouldBe 12
}
"testUncurrying" {
val sum2ints: (Int, Int) -> Int = { x, y -> x + y }
val curried: (Int) -> (Int) -> Int = sum2ints.curried()
curried(2)(4) shouldBe 6
// same type as sum2ints,
curried.uncurried()(2, 4) shouldBe 6
sum2ints(2, 4) shouldBe 6
}
"testCurryingEffect" {
val sum2ints: suspend (Int, Int) -> Int = { x: Int, y: Int -> x + y }
val curried: (Int) -> suspend (Int) -> Int = sum2ints.curried()
curried(2)(4) shouldBe 6
val add5: suspend (Int) -> Int = curried(5)
add5(7) shouldBe 12
}
"testUncurryingEffect" {
val sum2ints: suspend (Int, Int) -> Int = { x, y -> x + y }
val curried: (Int) -> suspend (Int) -> Int = sum2ints.curried()
curried(2)(4) shouldBe 6
// same type as sum2ints,
curried.uncurried()(2, 4) shouldBe 6
sum2ints(2, 4) shouldBe 6
}
"testTupling" {
val sum2ints = { x: Int, y: Int -> x + y }
val tupled = sum2ints.tupled()
tupled(Tuple2(2, 4)) shouldBe 6
}
"testUntupling" {
val sum2ints = { t: Tuple2<Int, Int> -> t.a + t.b }
val untupled = sum2ints.untupled()
untupled(2, 4) shouldBe 6
}
"memoize" {
var counterA = 0
var counterB = 0
val a = { _: Int -> counterA++ }
val b = { _: Int -> counterB++ }.memoize()
repeat(5) { a(1) }
repeat(5) { b(1) }
counterA shouldBe 5
counterB shouldBe 1 // calling several times a memoized function with the same parameter is computed just once
}
"memoizeEmpty" {
var counterA = 0
var counterB = 0
val a = { counterA++ }
val b = { counterB++ }.memoize()
repeat(5) { a() }
repeat(5) { b() }
counterA shouldBe 5
counterB shouldBe 1 // calling several times a memoized function with the same parameter is computed just once
}
"testPaired" {
val sum2ints = { x: Int, y: Int -> x + y }
val paired = sum2ints.paired()
val unpaired = paired.unpaired()
sum2ints(5, 9) shouldBe paired(5 to 9)
paired(5 to 9) shouldBe unpaired(5, 9)
}
"testTripled" {
val sum3ints = { x: Int, y: Int, z: Int -> x + y + z }
val tripled = sum3ints.tripled()
val untripled = tripled.untripled()
sum3ints(1, 2, 3) shouldBe tripled(Triple(1, 2, 3))
tripled(Triple(9, 8, 7)) shouldBe untripled(9, 8, 7)
}
"testReverse" {
val j: (String, List<String>) -> List<String> = f(p2 = 1)
j("x", listOf("a", "b", "c")) shouldBe j.reverse()(listOf("a", "b", "c"), "x")
}
"partially" {
val sum5ints = { a: Int, b: Int, c: Int, d: Int, e: Int -> a + b + c + d + e }
val sum4intsTo10 = sum5ints.partially5(10)
val sum3intsTo15 = sum4intsTo10.partially4(5)
val sum2intsTo17 = sum3intsTo15.partially3(2)
sum2intsTo17(1, 2) shouldBe 20
val prefixAndPostfix = { prefix: String, x: String, postfix: String -> "$prefix$x$postfix" }
val helloX = prefixAndPostfix.partially1("Hello, ").partially2("!")
helloX("Arrow") shouldBe "Hello, Arrow!"
}
"partials" {
val sum5ints = { a: Int, b: Int, c: Int, d: Int, e: Int -> a + b + c + d + e }
val sum4intsTo10: (Int, Int, Int, Int) -> Int = sum5ints(p5 = 10)
val sum3intsTo15: (Int, Int, Int) -> Int = sum4intsTo10(p4 = 5)
val sum2intsTo17: (Int, Int) -> Int = sum3intsTo15(p3 = 2)
sum2intsTo17(1, 2) shouldBe 20
val prefixAndPostfix = { prefix: String, x: String, postfix: String -> "$prefix$x$postfix" }
val helloX: (String) -> String = prefixAndPostfix(p1 = "Hello, ")(p2 = "!")
helloX("Arrow") shouldBe "Hello, Arrow!"
}
"bind" {
var i = 0
fun inc(a: Int) {
i += a
}
val binded = ::inc.bind(5)
i shouldBe 0
binded()
i shouldBe 5
}
}
}