diff --git a/lib/aiken/fuzz.ak b/lib/aiken/fuzz.ak
index e88b032..92cdb91 100644
--- a/lib/aiken/fuzz.ak
+++ b/lib/aiken/fuzz.ak
@@ -425,6 +425,147 @@ fn nub(n: Int, fuzzer: Fuzzer, st: List) -> Fuzzer {
}
}
+/// A convenient way of generating tuples instead of doing [`map2`](#map2)
+/// ```aiken
+/// map2(
+/// fuzzer_a, fuzzer_b,
+/// fn(a, b) { (a, b) }
+/// )
+/// ```
+pub fn tuple(a: Fuzzer, b: Fuzzer) -> Fuzzer<(a, b)> {
+ let a, b <- map2(a, b)
+ (a, b)
+}
+
+/// A convenient way of generating tuple3 instead of doing [`map3`](#map3)
+/// ```aiken
+/// map3(
+/// fuzzer_a, fuzzer_b, fuzzer_c,
+/// fn(a, b, c) { (a, b, c) }
+/// )
+/// ```
+pub fn tuple3(a: Fuzzer, b: Fuzzer, c: Fuzzer) -> Fuzzer<(a, b, c)> {
+ let a, b, c <- map3(a, b, c)
+ (a, b, c)
+}
+
+/// A convenient way of generating tuple4 instead of doing [`map4`](#map4)
+/// ```aiken
+/// map4(
+/// fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d,
+/// fn(a, b, c, d) { (a, b, c, d) }
+/// )
+/// ```
+pub fn tuple4(
+ a: Fuzzer,
+ b: Fuzzer,
+ c: Fuzzer,
+ d: Fuzzer,
+) -> Fuzzer<(a, b, c, d)> {
+ let a, b, c, d <- map4(a, b, c, d)
+ (a, b, c, d)
+}
+
+/// A convenient way of generating tuple5 instead of doing [`map5`](#map5)
+/// ```aiken
+/// map5(
+/// fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d, fuzzer_e,
+/// fn(a, b, c, d, e) { (a, b, c, d, e) }
+/// )
+/// ```
+pub fn tuple5(
+ a: Fuzzer,
+ b: Fuzzer,
+ c: Fuzzer,
+ d: Fuzzer,
+ e: Fuzzer,
+) -> Fuzzer<(a, b, c, d, e)> {
+ let a, b, c, d, e <- map5(a, b, c, d, e)
+ (a, b, c, d, e)
+}
+
+/// A convenient way of generating tuple6 instead of doing [`map6`](#map6)
+/// ```aiken
+/// map6(
+/// fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d, fuzzer_e, fuzzer_f,
+/// fn(a, b, c, d, e, f) { (a, b, c, d, e, f) }
+/// )
+/// ```
+pub fn tuple6(
+ a: Fuzzer,
+ b: Fuzzer,
+ c: Fuzzer,
+ d: Fuzzer,
+ e: Fuzzer,
+ f: Fuzzer,
+) -> Fuzzer<(a, b, c, d, e, f)> {
+ let a, b, c, d, e, f <- map6(a, b, c, d, e, f)
+ (a, b, c, d, e, f)
+}
+
+/// A convenient way of generating tuple7 instead of doing [`map7`](#map7)
+/// ```aiken
+/// map7(
+/// fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d, fuzzer_e, fuzzer_f, fuzzer_g,
+/// fn(a, b, c, d, e, f, g) { (a, b, c, d, e, f, g) }
+/// )
+/// ```
+pub fn tuple7(
+ a: Fuzzer,
+ b: Fuzzer,
+ c: Fuzzer,
+ d: Fuzzer,
+ e: Fuzzer,
+ f: Fuzzer,
+ g: Fuzzer,
+) -> Fuzzer<(a, b, c, d, e, f, g)> {
+ let a, b, c, d, e, f, g <- map7(a, b, c, d, e, f, g)
+ (a, b, c, d, e, f, g)
+}
+
+/// A convenient way of generating tuple8 instead of doing [`map8`](#map8)
+/// ```aiken
+/// map8(
+/// fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d, fuzzer_e, fuzzer_f, fuzzer_g, fuzzer_h,
+/// fn(a, b, c, d, e, f, g, h) { (a, b, c, d, e, f, g, h) }
+/// )
+/// ```
+pub fn tuple8(
+ a: Fuzzer,
+ b: Fuzzer,
+ c: Fuzzer,
+ d: Fuzzer,
+ e: Fuzzer,
+ f: Fuzzer,
+ g: Fuzzer,
+ h: Fuzzer,
+) -> Fuzzer<(a, b, c, d, e, f, g, h)> {
+ let a, b, c, d, e, f, g, h <- map8(a, b, c, d, e, f, g, h)
+ (a, b, c, d, e, f, g, h)
+}
+
+/// A convenient way of generating tuple9 instead of doing [`map9`](#map9)
+/// ```aiken
+/// map9(
+/// fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d, fuzzer_e, fuzzer_f, fuzzer_g, fuzzer_h, fuzzer_i,
+/// fn(a, b, c, d, e, f, g, h, i) { (a, b, c, d, e, f, g, h, i) }
+/// )
+/// ```
+pub fn tuple9(
+ a: Fuzzer,
+ b: Fuzzer,
+ c: Fuzzer,
+ d: Fuzzer,
+ e: Fuzzer,
+ f: Fuzzer,
+ g: Fuzzer,
+ h: Fuzzer,
+ i: Fuzzer,
+) -> Fuzzer<(a, b, c, d, e, f, g, h, i)> {
+ let a, b, c, d, e, f, g, h, i <- map9(a, b, c, d, e, f, g, h, i)
+ (a, b, c, d, e, f, g, h, i)
+}
+
// ## Combining
/// Combine a [Fuzzer](https://aiken-lang.github.io/prelude/aiken.html#Fuzzer) with the result of a another one.
diff --git a/lib/aiken/fuzz.test.ak b/lib/aiken/fuzz.test.ak
index a6e2e2d..dbc2ae5 100644
--- a/lib/aiken/fuzz.test.ak
+++ b/lib/aiken/fuzz.test.ak
@@ -1,8 +1,10 @@
use aiken/collection/list
use aiken/fuzz.{
- and_then, bool, constant, either3, either4, either5, either6, either7, either8,
- either9, int, int_between, label, list_between, list_with_elem, map, one_of,
- set, set_between, sublist, such_that,
+ and_then, bool, byte, bytearray, constant, either3, either4, either5, either6,
+ either7, either8, either9, int, int_between, label, list_between,
+ list_with_elem, map, map2, map3, map4, map5, map6, map7, map8, map9, one_of,
+ set, set_between, sublist, such_that, tuple, tuple3, tuple4, tuple5, tuple6,
+ tuple7, tuple8, tuple9,
}
use aiken/math
use aiken/primitive/bytearray
@@ -319,3 +321,324 @@ fn buckets(n, start, end, increment) -> Void {
buckets(n, next, end, increment)
}
}
+
+// ## Tuple Fuzzer Tests
+
+fn data_fuzzer() -> Fuzzer {
+ either4(
+ {
+ let bool <- map(bool())
+ let data: Data = bool
+ data
+ },
+ {
+ let byte <- map(byte())
+ let data: Data = byte
+ data
+ },
+ {
+ let bytearray <- map(bytearray())
+ let data: Data = bytearray
+ data
+ },
+ {
+ let int <- map(int())
+ let data: Data = int
+ data
+ },
+ )
+}
+
+fn prop_tuple2() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+
+ let l_tuple <- and_then(tuple(fuzzer_a, fuzzer_b))
+ let r_tuple <- and_then(map2(fuzzer_a, fuzzer_b, fn(a, b) { (a, b) }))
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple3() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+ let c <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+ let fuzzer_c = c |> constant
+
+ let l_tuple <- and_then(tuple3(fuzzer_a, fuzzer_b, fuzzer_c))
+ let r_tuple <-
+ and_then(map3(fuzzer_a, fuzzer_b, fuzzer_c, fn(a, b, c) { (a, b, c) }))
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple4() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+ let c <- and_then(data_fuzzer())
+ let d <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+ let fuzzer_c = c |> constant
+ let fuzzer_d = d |> constant
+
+ let l_tuple <- and_then(tuple4(fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d))
+ let r_tuple <-
+ and_then(
+ map4(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fn(a, b, c, d) { (a, b, c, d) },
+ ),
+ )
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple5() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+ let c <- and_then(data_fuzzer())
+ let d <- and_then(data_fuzzer())
+ let e <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+ let fuzzer_c = c |> constant
+ let fuzzer_d = d |> constant
+ let fuzzer_e = e |> constant
+
+ let l_tuple <-
+ and_then(tuple5(fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d, fuzzer_e))
+ let r_tuple <-
+ and_then(
+ map5(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fn(a, b, c, d, e) { (a, b, c, d, e) },
+ ),
+ )
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple6() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+ let c <- and_then(data_fuzzer())
+ let d <- and_then(data_fuzzer())
+ let e <- and_then(data_fuzzer())
+ let f <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+ let fuzzer_c = c |> constant
+ let fuzzer_d = d |> constant
+ let fuzzer_e = e |> constant
+ let fuzzer_f = f |> constant
+
+ let l_tuple <-
+ and_then(tuple6(fuzzer_a, fuzzer_b, fuzzer_c, fuzzer_d, fuzzer_e, fuzzer_f))
+ let r_tuple <-
+ and_then(
+ map6(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fuzzer_f,
+ fn(a, b, c, d, e, f) { (a, b, c, d, e, f) },
+ ),
+ )
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple7() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+ let c <- and_then(data_fuzzer())
+ let d <- and_then(data_fuzzer())
+ let e <- and_then(data_fuzzer())
+ let f <- and_then(data_fuzzer())
+ let g <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+ let fuzzer_c = c |> constant
+ let fuzzer_d = d |> constant
+ let fuzzer_e = e |> constant
+ let fuzzer_f = f |> constant
+ let fuzzer_g = g |> constant
+
+ let l_tuple <-
+ and_then(
+ tuple7(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fuzzer_f,
+ fuzzer_g,
+ ),
+ )
+ let r_tuple <-
+ and_then(
+ map7(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fuzzer_f,
+ fuzzer_g,
+ fn(a, b, c, d, e, f, g) { (a, b, c, d, e, f, g) },
+ ),
+ )
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple8() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+ let c <- and_then(data_fuzzer())
+ let d <- and_then(data_fuzzer())
+ let e <- and_then(data_fuzzer())
+ let f <- and_then(data_fuzzer())
+ let g <- and_then(data_fuzzer())
+ let h <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+ let fuzzer_c = c |> constant
+ let fuzzer_d = d |> constant
+ let fuzzer_e = e |> constant
+ let fuzzer_f = f |> constant
+ let fuzzer_g = g |> constant
+ let fuzzer_h = h |> constant
+
+ let l_tuple <-
+ and_then(
+ tuple8(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fuzzer_f,
+ fuzzer_g,
+ fuzzer_h,
+ ),
+ )
+ let r_tuple <-
+ and_then(
+ map8(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fuzzer_f,
+ fuzzer_g,
+ fuzzer_h,
+ fn(a, b, c, d, e, f, g, h) { (a, b, c, d, e, f, g, h) },
+ ),
+ )
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple9() -> Fuzzer {
+ let a <- and_then(data_fuzzer())
+ let b <- and_then(data_fuzzer())
+ let c <- and_then(data_fuzzer())
+ let d <- and_then(data_fuzzer())
+ let e <- and_then(data_fuzzer())
+ let f <- and_then(data_fuzzer())
+ let g <- and_then(data_fuzzer())
+ let h <- and_then(data_fuzzer())
+ let i <- and_then(data_fuzzer())
+
+ let fuzzer_a = a |> constant
+ let fuzzer_b = b |> constant
+ let fuzzer_c = c |> constant
+ let fuzzer_d = d |> constant
+ let fuzzer_e = e |> constant
+ let fuzzer_f = f |> constant
+ let fuzzer_g = g |> constant
+ let fuzzer_h = h |> constant
+ let fuzzer_i = i |> constant
+
+ let l_tuple <-
+ and_then(
+ tuple9(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fuzzer_f,
+ fuzzer_g,
+ fuzzer_h,
+ fuzzer_i,
+ ),
+ )
+ let r_tuple <-
+ and_then(
+ map9(
+ fuzzer_a,
+ fuzzer_b,
+ fuzzer_c,
+ fuzzer_d,
+ fuzzer_e,
+ fuzzer_f,
+ fuzzer_g,
+ fuzzer_h,
+ fuzzer_i,
+ fn(a, b, c, d, e, f, g, h, i) { (a, b, c, d, e, f, g, h, i) },
+ ),
+ )
+
+ constant(l_tuple == r_tuple)
+}
+
+fn prop_tuple2_to_tuple9() -> Fuzzer {
+ let tuple2_map2 <- and_then(prop_tuple2())
+ let tuple3_map3 <- and_then(prop_tuple3())
+ let tuple4_map4 <- and_then(prop_tuple4())
+ let tuple5_map5 <- and_then(prop_tuple5())
+ let tuple6_map6 <- and_then(prop_tuple6())
+ let tuple7_map7 <- and_then(prop_tuple7())
+ let tuple8_map8 <- and_then(prop_tuple8())
+ let tuple9_map9 <- and_then(prop_tuple9())
+
+ constant(and {
+ tuple2_map2,
+ tuple3_map3,
+ tuple4_map4,
+ tuple5_map5,
+ tuple6_map6,
+ tuple7_map7,
+ tuple8_map8,
+ tuple9_map9,
+ })
+}
+
+test prop_tuples(match via prop_tuple2_to_tuple9()) {
+ match
+}