From bbf59763137b83df5e22d29281740dec09d3b5ed Mon Sep 17 00:00:00 2001 From: Franco Luque Date: Fri, 8 Sep 2023 18:08:34 -0300 Subject: [PATCH 01/45] new math function sqrt_is --- lib/aiken/math.ak | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/aiken/math.ak b/lib/aiken/math.ak index ae8941b..245baf3 100644 --- a/lib/aiken/math.ak +++ b/lib/aiken/math.ak @@ -349,3 +349,24 @@ test sqrt5() { test sqrt6() { sqrt(-42) == None } + +/// Checks if an integer has a given integer square root x. +/// The check has constant time complexity (O(1)). +/// +/// ```aiken +/// math.sqrt_is(0, 0) +/// math.sqrt_is(25, 5) +/// !math.sqrt_is(25, -5) +/// math.sqrt_is(44203, 210) +/// ``` +pub fn sqrt_is(self: Int, x: Int) -> Bool { + x * x <= self && (x+1) * (x+1) > self +} + +test sqrt_is1() { + sqrt_is(44203, 210) +} + +test sqrt_is2() { + sqrt_is(975461057789971041, 987654321) +} From 52eb39f40d0e672bd0e5d086451bfc4afd562ddf Mon Sep 17 00:00:00 2001 From: Franco Luque Date: Mon, 11 Sep 2023 15:40:01 -0300 Subject: [PATCH 02/45] rename sqrt_is to is_sqrt and fix format --- lib/aiken/math.ak | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/aiken/math.ak b/lib/aiken/math.ak index 245baf3..764152b 100644 --- a/lib/aiken/math.ak +++ b/lib/aiken/math.ak @@ -354,19 +354,19 @@ test sqrt6() { /// The check has constant time complexity (O(1)). /// /// ```aiken -/// math.sqrt_is(0, 0) -/// math.sqrt_is(25, 5) -/// !math.sqrt_is(25, -5) -/// math.sqrt_is(44203, 210) +/// math.is_sqrt(0, 0) +/// math.is_sqrt(25, 5) +/// ! math.is_sqrt(25, -5) +/// math.is_sqrt(44203, 210) /// ``` -pub fn sqrt_is(self: Int, x: Int) -> Bool { - x * x <= self && (x+1) * (x+1) > self +pub fn is_sqrt(self: Int, x: Int) -> Bool { + x * x <= self && ( x + 1 ) * ( x + 1 ) > self } -test sqrt_is1() { - sqrt_is(44203, 210) +test is_sqrt1() { + is_sqrt(44203, 210) } -test sqrt_is2() { - sqrt_is(975461057789971041, 987654321) +test is_sqrt2() { + is_sqrt(975461057789971041, 987654321) } From 2725b16e45141630354113d8ea31293b044c13b4 Mon Sep 17 00:00:00 2001 From: microproofs Date: Sat, 2 Mar 2024 14:00:15 -0500 Subject: [PATCH 03/45] bump version to 1.7.0 to match release --- aiken.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiken.toml b/aiken.toml index 3affc23..b830018 100644 --- a/aiken.toml +++ b/aiken.toml @@ -1,5 +1,5 @@ name = "aiken-lang/stdlib" -version = "1.6.0" +version = "1.7.0" licences = ["Apache-2.0"] description = "The Aiken Standard Library" From fc3b9d54c161e47445c7190a64d85d3a9fc020d0 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 14 Mar 2024 15:22:29 +0100 Subject: [PATCH 04/45] Add disclaimer on bytearray.to_string --- lib/aiken/bytearray.ak | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/aiken/bytearray.ak b/lib/aiken/bytearray.ak index 0a7987d..c9eb3f3 100644 --- a/lib/aiken/bytearray.ak +++ b/lib/aiken/bytearray.ak @@ -387,8 +387,14 @@ test take_4() { /// Convert a `ByteArray` into a `String`. /// +///
⚠️
WARNING
| This functions fails if the underlying `ByteArray` isn't UTF-8-encoded.
In particular, you cannot convert arbitrary hash digests using this function.
For converting arbitrary `ByteArray`s, use [bytearray.to_hex](#to_hex). +/// --- | --- +/// +/// /// ```aiken /// bytearray.to_string(#"414243") == "ABC" +/// +/// bytearray.to_string(some_hash) -> fail /// ``` pub fn to_string(self: ByteArray) -> String { builtin.decode_utf8(self) From b57389f22870f05fb46a10caf0132e3e7588c60c Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 14 Mar 2024 15:25:32 +0100 Subject: [PATCH 05/45] Also add disclaimer on string.from_bytearray --- lib/aiken/string.ak | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/aiken/string.ak b/lib/aiken/string.ak index 093cb0d..11d7179 100644 --- a/lib/aiken/string.ak +++ b/lib/aiken/string.ak @@ -26,9 +26,15 @@ test concat_3() { /// Convert a `ByteArray` into a `String` /// +///
⚠️
WARNING
| This functions fails if the underlying `ByteArray` isn't UTF-8-encoded.
In particular, you cannot convert arbitrary hash digests using this function.
For converting arbitrary `ByteArray`s, use [bytearray.to_hex](../bytearray.html#to_hex). +/// --- | --- +/// /// ```aiken /// string.from_bytearray("foo") == @"foo" +/// /// string.from_bytearray(#"666f6f") == @"foo" +/// +/// string.from_bytearray(some_hash) -> fail /// ``` pub fn from_bytearray(bytes: ByteArray) -> String { decode_utf8(bytes) From 65a63d846d77ada5eb95dcb93c90cd86649b6efc Mon Sep 17 00:00:00 2001 From: Micah <66159982+micahkendall@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:01:33 +1100 Subject: [PATCH 06/45] Add value.reduce into transaction/value.ak --- lib/aiken/transaction/value.ak | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index ff4dd95..628affb 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -378,6 +378,57 @@ test flatten_with_2() { ) == [("a", "2"), ("b", "")] } +/// Reduce a value into a single result +/// +/// This is a foldr inside a foldr on the nested dictionaries +pub fn reduce( + self: Value, + start: result, + with: fn(PolicyId, AssetName, Int, result) -> result, +) -> result { + dict.foldr( + self.inner, + start, + fn(policy_id, asset_list, value) { + dict.foldr(asset_list, value, with(policy_id, _, _, _)) + }, + ) +} + +test reduce_1() { + let v = + zero() + |> add("a", "1", 10) + |> add("b", "2", 20) + let result = reduce(v, 0, fn(_, _, quantity, acc) { acc + quantity }) + result == 30 +} + +test reduce_2() { + let v = + zero() + |> add("a", "1", 5) + |> add("a", "2", 15) + |> add("b", "", 10) + let result = + reduce( + v, + [], + fn(policy_id, asset_name, _, acc) { [(policy_id, asset_name), ..acc] }, + ) + result == [("a", "1"), ("a", "2"), ("b", "")] +} + +test reduce_3() { + let v = + zero() + |> add("a", "1", 3) + |> add("b", "2", 6) + |> add("c", "3", 9) + let result = reduce(v, 1, fn(_, _, quantity, acc) { acc * quantity }) + result == 162 +} + /// Convert the value into a dictionary of dictionaries. pub fn to_dict(self: Value) -> Dict> { self.inner From 229f3ceb8a270b9ad37f78d0eb82659314e9a326 Mon Sep 17 00:00:00 2001 From: Micah <66159982+micahkendall@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:08:49 +1100 Subject: [PATCH 07/45] Update value.ak result -> acc --- lib/aiken/transaction/value.ak | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 628affb..3901d81 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -383,9 +383,9 @@ test flatten_with_2() { /// This is a foldr inside a foldr on the nested dictionaries pub fn reduce( self: Value, - start: result, - with: fn(PolicyId, AssetName, Int, result) -> result, -) -> result { + start: acc, + with: fn(PolicyId, AssetName, Int, acc) -> acc, +) -> acc { dict.foldr( self.inner, start, From 3a8e77c5ae2c431a472bf27bbe0a8d7e8fcfc125 Mon Sep 17 00:00:00 2001 From: Micah Kendall Date: Fri, 15 Mar 2024 19:21:08 +1100 Subject: [PATCH 08/45] requested changes --- lib/aiken/transaction/value.ak | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 3901d81..0c4a7dc 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -380,7 +380,13 @@ test flatten_with_2() { /// Reduce a value into a single result /// -/// This is a foldr inside a foldr on the nested dictionaries +/// ``` +/// zero() +/// |> add("a", "1", 10) +/// |> add("b", "2", 20) +/// |> value.reduce(v, 0, fn(_, _, quantity, acc) { acc + quantity }) +/// // 30 +/// ``` pub fn reduce( self: Value, start: acc, @@ -512,10 +518,10 @@ test from_minted_value_5() { pub fn to_minted_value(self: Value) -> MintedValue { self.inner |> dict.insert( - ada_policy_id, - dict.insert(dict.new(), ada_asset_name, 0, bytearray.compare), - bytearray.compare, - ) + ada_policy_id, + dict.insert(dict.new(), ada_asset_name, 0, bytearray.compare), + bytearray.compare, + ) |> MintedValue } From 3e47bb8a81de35faa45f50ae25c89eb8ed2c841d Mon Sep 17 00:00:00 2001 From: Micah Kendall Date: Fri, 15 Mar 2024 19:23:02 +1100 Subject: [PATCH 09/45] bump CI version --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index e6d2b5e..f88177b 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -33,7 +33,7 @@ jobs: - name: 🧰 Install Aiken uses: aiken-lang/setup-aiken@v0.1.0 with: - version: v1.0.18-alpha + version: v1.0.24-alpha - name: 📝 Run fmt run: aiken fmt --check From d8dcf4e40b4521e49ccd855778fa387cefe0a01d Mon Sep 17 00:00:00 2001 From: Micah Kendall Date: Fri, 15 Mar 2024 19:23:33 +1100 Subject: [PATCH 10/45] fmt other --- lib/aiken/cbor.ak | 6 ++-- lib/aiken/dict.ak | 59 ++++++++++---------------------------- lib/aiken/int.ak | 40 +++++++++++++------------- lib/aiken/math/rational.ak | 12 ++++---- lib/aiken/transaction.ak | 56 ++++++++++++++++++------------------ 5 files changed, 72 insertions(+), 101 deletions(-) diff --git a/lib/aiken/cbor.ak b/lib/aiken/cbor.ak index 7f0db02..7de71e7 100644 --- a/lib/aiken/cbor.ak +++ b/lib/aiken/cbor.ak @@ -201,9 +201,9 @@ fn do_diagnostic(self: Data, builder: ByteArray) -> ByteArray { bytes |> encode_base16( - length_of_bytearray(bytes) - 1, - append_bytearray(#"27", builder), - ) + length_of_bytearray(bytes) - 1, + append_bytearray(#"27", builder), + ) |> append_bytearray(#"6827", _) }, ) diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index fe17ade..c223750 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -57,21 +57,18 @@ fn fixture_1() { /// /// result == [(2, 200)] /// ``` -pub fn delete(self: Dict, key: key) -> Dict { - Dict { inner: do_delete(self.inner, key) } -} - -fn do_delete(self: List<(key, value)>, key k: key) -> List<(key, value)> { - when self is { +pub fn delete(self: Dict, k: key) -> Dict { + when self.inner is { [] -> [] - [(k2, v2), ..rest] -> - if k == k2 { + [v, ..rest] -> + if k == v.1st { rest } else { - [(k2, v2), ..do_delete(rest, k)] + [v, ..delete(Dict(rest), k).inner] } } + |> Dict() } test delete_1() { @@ -183,17 +180,13 @@ test filter_3() { /// result == Some(foo) /// ``` pub fn find(self: Dict, value v: value) -> Option { - do_find(self.inner, v) -} - -fn do_find(self: List<(key, value)>, value v: value) -> Option { - when self is { + when self.inner is { [] -> None [(k2, v2), ..rest] -> if v == v2 { Some(k2) } else { - do_find(rest, v) + find(Dict(rest), v) } } } @@ -248,17 +241,9 @@ pub fn foldr( zero: result, with: fn(key, value, result) -> result, ) -> result { - do_foldr(self.inner, zero, with) -} - -fn do_foldr( - self: List<(key, value)>, - zero: result, - with: fn(key, value, result) -> result, -) -> result { - when self is { + when self.inner is { [] -> zero - [(k, v), ..rest] -> with(k, v, do_foldr(rest, zero, with)) + [(k, v), ..rest] -> with(k, v, foldr(Dict(rest), zero, with)) } } @@ -290,17 +275,9 @@ pub fn foldl( zero: result, with: fn(key, value, result) -> result, ) -> result { - do_foldl(self.inner, zero, with) -} - -fn do_foldl( - self: List<(key, value)>, - zero: result, - with: fn(key, value, result) -> result, -) -> result { - when self is { + when self.inner is { [] -> zero - [(k, v), ..rest] -> do_foldl(rest, with(k, v, zero), with) + [(k, v), ..rest] -> foldl(Dict(rest), with(k, v, zero), with) } } @@ -330,18 +307,12 @@ pub fn from_list( self: List<(key, value)>, compare: fn(key, key) -> Ordering, ) -> Dict { - Dict { inner: do_from_list(self, compare) } -} - -fn do_from_list( - xs: List<(key, value)>, - compare: fn(key, key) -> Ordering, -) -> List<(key, value)> { - when xs is { + when self is { [] -> [] - [(k, v), ..rest] -> do_insert(do_from_list(rest, compare), k, v, compare) + [(k, v), ..rest] -> do_insert(from_list(rest, compare).inner, k, v, compare) } + |> Dict() } test from_list_1() { diff --git a/lib/aiken/int.ak b/lib/aiken/int.ak index b0e7524..fd602b6 100644 --- a/lib/aiken/int.ak +++ b/lib/aiken/int.ak @@ -32,26 +32,26 @@ pub fn compare(left: Int, right: Int) -> Ordering { pub fn from_utf8(bytes: ByteArray) -> Option { bytes |> bytearray.foldr( - Some((0, 0)), - fn(byte, st) { - when st is { - None -> None - Some((n, e)) -> - if byte < 48 || byte > 57 { - if byte == 45 { - Some((-n, 0)) - } else { - None - } - } else if n < 0 { - None - } else { - let digit = byte - 48 - Some((n + digit * math.pow(10, e), e + 1)) - } - } - }, - ) + Some((0, 0)), + fn(byte, st) { + when st is { + None -> None + Some((n, e)) -> + if byte < 48 || byte > 57 { + if byte == 45 { + Some((-n, 0)) + } else { + None + } + } else if n < 0 { + None + } else { + let digit = byte - 48 + Some((n + digit * math.pow(10, e), e + 1)) + } + } + }, + ) |> option.map(fn(tuple) { tuple.1st }) } diff --git a/lib/aiken/math/rational.ak b/lib/aiken/math/rational.ak index e62a65d..6e0ec04 100644 --- a/lib/aiken/math/rational.ak +++ b/lib/aiken/math/rational.ak @@ -644,7 +644,7 @@ test compare_with_eq() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - !eq(x, y)? && !eq(y, x)? && eq(x, x)? + !eq(x, y)? && ( !eq(y, x)? && eq(x, x)? ) } test compare_with_neq() { @@ -654,7 +654,7 @@ test compare_with_neq() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - neq(x, y)? && neq(y, x)? && !neq(x, x)? + neq(x, y)? && ( neq(y, x)? && !neq(x, x)? ) } test compare_with_gte() { @@ -664,7 +664,7 @@ test compare_with_gte() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - !gte(x, y)? && gte(y, x)? && gte(x, x)? + !gte(x, y)? && ( gte(y, x)? && gte(x, x)? ) } test compare_with_gt() { @@ -674,7 +674,7 @@ test compare_with_gt() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - !gt(x, y)? && gt(y, x)? && !gt(x, x)? + !gt(x, y)? && ( gt(y, x)? && !gt(x, x)? ) } test compare_with_lte() { @@ -684,7 +684,7 @@ test compare_with_lte() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - lte(x, y)? && !lte(y, x)? && lte(x, x)? + lte(x, y)? && ( !lte(y, x)? && lte(x, x)? ) } test compare_with_lt() { @@ -694,7 +694,7 @@ test compare_with_lt() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - lt(x, y)? && !lt(y, x)? && !lt(x, x)? + lt(x, y)? && ( !lt(y, x)? && !lt(x, x)? ) } /// Calculate the arithmetic mean between two `Rational` values. diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index 6b3cbb1..fb020ed 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -183,26 +183,26 @@ pub fn find_datum( datums |> dict.get(datum_hash) |> option.or_try( - fn() { - outputs - |> list.filter_map( - fn(output) { - when output.datum is { - InlineDatum(data) -> - if - blake2b_256(builtin.serialise_data(data)) == datum_hash{ - - Some(data) - } else { - None - } - _ -> None - } - }, - ) - |> list.head - }, - ) + fn() { + outputs + |> list.filter_map( + fn(output) { + when output.datum is { + InlineDatum(data) -> + if + blake2b_256(builtin.serialise_data(data)) == datum_hash{ + + Some(data) + } else { + None + } + _ -> None + } + }, + ) + |> list.head + }, + ) } /// Find all outputs that are paying into the given script hash, if any. This is useful for @@ -213,12 +213,12 @@ pub fn find_script_outputs( ) -> List { outputs |> list.filter( - fn(output) { - when output.address.payment_credential is { - ScriptCredential(addr_script_hash) -> - script_hash == addr_script_hash - VerificationKeyCredential(_) -> False - } - }, - ) + fn(output) { + when output.address.payment_credential is { + ScriptCredential(addr_script_hash) -> + script_hash == addr_script_hash + VerificationKeyCredential(_) -> False + } + }, + ) } From 28d1268aed8e19e251ed3d65a1ef9d78a6aab581 Mon Sep 17 00:00:00 2001 From: Micah Kendall Date: Fri, 15 Mar 2024 19:24:38 +1100 Subject: [PATCH 11/45] fmt older aiken --- lib/aiken/cbor.ak | 6 ++-- lib/aiken/int.ak | 40 ++++++++++++------------ lib/aiken/transaction.ak | 56 +++++++++++++++++----------------- lib/aiken/transaction/value.ak | 8 ++--- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/lib/aiken/cbor.ak b/lib/aiken/cbor.ak index 7de71e7..7f0db02 100644 --- a/lib/aiken/cbor.ak +++ b/lib/aiken/cbor.ak @@ -201,9 +201,9 @@ fn do_diagnostic(self: Data, builder: ByteArray) -> ByteArray { bytes |> encode_base16( - length_of_bytearray(bytes) - 1, - append_bytearray(#"27", builder), - ) + length_of_bytearray(bytes) - 1, + append_bytearray(#"27", builder), + ) |> append_bytearray(#"6827", _) }, ) diff --git a/lib/aiken/int.ak b/lib/aiken/int.ak index fd602b6..b0e7524 100644 --- a/lib/aiken/int.ak +++ b/lib/aiken/int.ak @@ -32,26 +32,26 @@ pub fn compare(left: Int, right: Int) -> Ordering { pub fn from_utf8(bytes: ByteArray) -> Option { bytes |> bytearray.foldr( - Some((0, 0)), - fn(byte, st) { - when st is { - None -> None - Some((n, e)) -> - if byte < 48 || byte > 57 { - if byte == 45 { - Some((-n, 0)) - } else { - None - } - } else if n < 0 { - None - } else { - let digit = byte - 48 - Some((n + digit * math.pow(10, e), e + 1)) - } - } - }, - ) + Some((0, 0)), + fn(byte, st) { + when st is { + None -> None + Some((n, e)) -> + if byte < 48 || byte > 57 { + if byte == 45 { + Some((-n, 0)) + } else { + None + } + } else if n < 0 { + None + } else { + let digit = byte - 48 + Some((n + digit * math.pow(10, e), e + 1)) + } + } + }, + ) |> option.map(fn(tuple) { tuple.1st }) } diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index fb020ed..6b3cbb1 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -183,26 +183,26 @@ pub fn find_datum( datums |> dict.get(datum_hash) |> option.or_try( - fn() { - outputs - |> list.filter_map( - fn(output) { - when output.datum is { - InlineDatum(data) -> - if - blake2b_256(builtin.serialise_data(data)) == datum_hash{ - - Some(data) - } else { - None - } - _ -> None - } - }, - ) - |> list.head - }, - ) + fn() { + outputs + |> list.filter_map( + fn(output) { + when output.datum is { + InlineDatum(data) -> + if + blake2b_256(builtin.serialise_data(data)) == datum_hash{ + + Some(data) + } else { + None + } + _ -> None + } + }, + ) + |> list.head + }, + ) } /// Find all outputs that are paying into the given script hash, if any. This is useful for @@ -213,12 +213,12 @@ pub fn find_script_outputs( ) -> List { outputs |> list.filter( - fn(output) { - when output.address.payment_credential is { - ScriptCredential(addr_script_hash) -> - script_hash == addr_script_hash - VerificationKeyCredential(_) -> False - } - }, - ) + fn(output) { + when output.address.payment_credential is { + ScriptCredential(addr_script_hash) -> + script_hash == addr_script_hash + VerificationKeyCredential(_) -> False + } + }, + ) } diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 0c4a7dc..dee89f1 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -518,10 +518,10 @@ test from_minted_value_5() { pub fn to_minted_value(self: Value) -> MintedValue { self.inner |> dict.insert( - ada_policy_id, - dict.insert(dict.new(), ada_asset_name, 0, bytearray.compare), - bytearray.compare, - ) + ada_policy_id, + dict.insert(dict.new(), ada_asset_name, 0, bytearray.compare), + bytearray.compare, + ) |> MintedValue } From 5edf42239097c6265a83e4da7b5ae85b53448f4b Mon Sep 17 00:00:00 2001 From: Micah <66159982+micahkendall@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:35:30 +1100 Subject: [PATCH 12/45] Update lib/aiken/transaction/value.ak Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- lib/aiken/transaction/value.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index dee89f1..8668837 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -381,7 +381,7 @@ test flatten_with_2() { /// Reduce a value into a single result /// /// ``` -/// zero() +/// value.zero() /// |> add("a", "1", 10) /// |> add("b", "2", 20) /// |> value.reduce(v, 0, fn(_, _, quantity, acc) { acc + quantity }) From f0d151a0e8ad64d892093da25acfe796d5a48d3b Mon Sep 17 00:00:00 2001 From: Micah <66159982+micahkendall@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:35:36 +1100 Subject: [PATCH 13/45] Update lib/aiken/transaction/value.ak Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- lib/aiken/transaction/value.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 8668837..433c232 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -382,7 +382,7 @@ test flatten_with_2() { /// /// ``` /// value.zero() -/// |> add("a", "1", 10) +/// |> value.add("a", "1", 10) /// |> add("b", "2", 20) /// |> value.reduce(v, 0, fn(_, _, quantity, acc) { acc + quantity }) /// // 30 From 28c935d383e8ed5b4c0024ee287aaf3f779bb0e2 Mon Sep 17 00:00:00 2001 From: Micah <66159982+micahkendall@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:35:42 +1100 Subject: [PATCH 14/45] Update lib/aiken/transaction/value.ak Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- lib/aiken/transaction/value.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 433c232..87af96f 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -383,7 +383,7 @@ test flatten_with_2() { /// ``` /// value.zero() /// |> value.add("a", "1", 10) -/// |> add("b", "2", 20) +/// |> value.add("b", "2", 20) /// |> value.reduce(v, 0, fn(_, _, quantity, acc) { acc + quantity }) /// // 30 /// ``` From 852b5249d88cf0223799727ed63784b97d958869 Mon Sep 17 00:00:00 2001 From: Micah <66159982+micahkendall@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:35:48 +1100 Subject: [PATCH 15/45] Update lib/aiken/transaction/value.ak Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- lib/aiken/transaction/value.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 87af96f..8a7ce18 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -395,7 +395,7 @@ pub fn reduce( dict.foldr( self.inner, start, - fn(policy_id, asset_list, value) { + fn(policy_id, asset_list, result) { dict.foldr(asset_list, value, with(policy_id, _, _, _)) }, ) From 79e368f44147bf8e841404700c2881e1e05daa22 Mon Sep 17 00:00:00 2001 From: Micah <66159982+micahkendall@users.noreply.github.com> Date: Fri, 15 Mar 2024 19:35:55 +1100 Subject: [PATCH 16/45] Update lib/aiken/transaction/value.ak Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- lib/aiken/transaction/value.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 8a7ce18..11430b9 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -396,7 +396,7 @@ pub fn reduce( self.inner, start, fn(policy_id, asset_list, result) { - dict.foldr(asset_list, value, with(policy_id, _, _, _)) + dict.foldr(asset_list, result, with(policy_id, _, _, _)) }, ) } From 85bb70af3cb9a7bf625daf8734bca42aa10c0e9d Mon Sep 17 00:00:00 2001 From: Micah Kendall Date: Fri, 15 Mar 2024 19:37:20 +1100 Subject: [PATCH 17/45] redundant test case change --- lib/aiken/transaction/value.ak | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 11430b9..aa630e1 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -426,13 +426,9 @@ test reduce_2() { } test reduce_3() { - let v = - zero() - |> add("a", "1", 3) - |> add("b", "2", 6) - |> add("c", "3", 9) - let result = reduce(v, 1, fn(_, _, quantity, acc) { acc * quantity }) - result == 162 + let v = zero() + let result = reduce(v, 1, fn(_, _, quantity, acc) { acc + quantity }) + result == 1 } /// Convert the value into a dictionary of dictionaries. From 28e0ead6063c1aa0671e1252358456ffe71db885 Mon Sep 17 00:00:00 2001 From: Micah Kendall Date: Fri, 15 Mar 2024 19:39:44 +1100 Subject: [PATCH 18/45] remove dict changes --- lib/aiken/dict.ak | 59 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index c223750..fe17ade 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -57,18 +57,21 @@ fn fixture_1() { /// /// result == [(2, 200)] /// ``` -pub fn delete(self: Dict, k: key) -> Dict { - when self.inner is { +pub fn delete(self: Dict, key: key) -> Dict { + Dict { inner: do_delete(self.inner, key) } +} + +fn do_delete(self: List<(key, value)>, key k: key) -> List<(key, value)> { + when self is { [] -> [] - [v, ..rest] -> - if k == v.1st { + [(k2, v2), ..rest] -> + if k == k2 { rest } else { - [v, ..delete(Dict(rest), k).inner] + [(k2, v2), ..do_delete(rest, k)] } } - |> Dict() } test delete_1() { @@ -180,13 +183,17 @@ test filter_3() { /// result == Some(foo) /// ``` pub fn find(self: Dict, value v: value) -> Option { - when self.inner is { + do_find(self.inner, v) +} + +fn do_find(self: List<(key, value)>, value v: value) -> Option { + when self is { [] -> None [(k2, v2), ..rest] -> if v == v2 { Some(k2) } else { - find(Dict(rest), v) + do_find(rest, v) } } } @@ -241,9 +248,17 @@ pub fn foldr( zero: result, with: fn(key, value, result) -> result, ) -> result { - when self.inner is { + do_foldr(self.inner, zero, with) +} + +fn do_foldr( + self: List<(key, value)>, + zero: result, + with: fn(key, value, result) -> result, +) -> result { + when self is { [] -> zero - [(k, v), ..rest] -> with(k, v, foldr(Dict(rest), zero, with)) + [(k, v), ..rest] -> with(k, v, do_foldr(rest, zero, with)) } } @@ -275,9 +290,17 @@ pub fn foldl( zero: result, with: fn(key, value, result) -> result, ) -> result { - when self.inner is { + do_foldl(self.inner, zero, with) +} + +fn do_foldl( + self: List<(key, value)>, + zero: result, + with: fn(key, value, result) -> result, +) -> result { + when self is { [] -> zero - [(k, v), ..rest] -> foldl(Dict(rest), with(k, v, zero), with) + [(k, v), ..rest] -> do_foldl(rest, with(k, v, zero), with) } } @@ -307,12 +330,18 @@ pub fn from_list( self: List<(key, value)>, compare: fn(key, key) -> Ordering, ) -> Dict { - when self is { + Dict { inner: do_from_list(self, compare) } +} + +fn do_from_list( + xs: List<(key, value)>, + compare: fn(key, key) -> Ordering, +) -> List<(key, value)> { + when xs is { [] -> [] - [(k, v), ..rest] -> do_insert(from_list(rest, compare).inner, k, v, compare) + [(k, v), ..rest] -> do_insert(do_from_list(rest, compare), k, v, compare) } - |> Dict() } test from_list_1() { From 871338cce70b55b2b93e4eebbfaaa2e88e3f7ad9 Mon Sep 17 00:00:00 2001 From: microproofs Date: Fri, 22 Mar 2024 13:11:05 -0400 Subject: [PATCH 19/45] feat: Add from asset list to stdlib Co-authored-by: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> --- lib/aiken/dict.ak | 35 +++++++++++ lib/aiken/transaction/value.ak | 104 +++++++++++++++++++++++++++++---- 2 files changed, 128 insertions(+), 11 deletions(-) diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index fe17ade..7507362 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -433,6 +433,41 @@ fn check_ascending_list( } } +pub fn from_ascending_list_with( + xs: List<(key, value)>, + compare: fn(key, key) -> Ordering, + value_predicate: fn(value) -> Bool, +) -> Dict { + let Void = check_ascending_list_with(xs, compare, value_predicate) + Dict { inner: xs } +} + +fn check_ascending_list_with( + xs: List<(key, value)>, + compare: fn(key, key) -> Ordering, + value_predicate: fn(value) -> Bool, +) { + when xs is { + [] -> Void + [(_, v)] -> + if value_predicate(v) { + Void + } else { + fail @"value doesn't satisfy predicate" + } + [(x0, v0), (x1, _) as e, ..rest] -> + when compare(x0, x1) is { + Less -> + if value_predicate(v0) { + check_ascending_list_with([e, ..rest], compare, value_predicate) + } else { + fail @"value doesn't satisfy predicate" + } + _ -> fail @"keys in associative list aren't in ascending order" + } + } +} + test bench_from_ascending_list() { let dict = from_ascending_list( diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index aa630e1..8f0fcb9 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -1,5 +1,5 @@ use aiken/bytearray -use aiken/dict.{Dict} +use aiken/dict.{Dict, from_ascending_list_with} use aiken/hash.{Blake2b_224, Hash} use aiken/list use aiken/option @@ -431,6 +431,86 @@ test reduce_3() { result == 1 } +pub fn from_asset_list(xs: List<(PolicyId, List<(AssetName, Int)>)>) -> Value { + xs + |> list.foldr( + dict.new(), + fn(inner, acc) { + expect (p, [_, ..] as x) = inner + x + |> from_ascending_list_with(bytearray.compare, fn(v) { v != 0 }) + |> dict.insert_with( + acc, + p, + _, + fn(_, _, _) { + fail @"Duplicate policy in the asset list." + }, + bytearray.compare, + ) + }, + ) + |> Value +} + +test from_asset_list_1() { + let v = from_asset_list([]) + v == zero() +} + +test from_asset_list_2() fail { + let v = from_asset_list([(#"33", [])]) + v == zero() +} + +test from_asset_list_3() fail { + let v = from_asset_list([(#"33", [(#"", 0)])]) + v == zero() +} + +test from_asset_list_4() { + let v = from_asset_list([(#"33", [(#"", 1)])]) + flatten(v) == [(#"33", #"", 1)] +} + +test from_asset_list_5() { + let v = from_asset_list([(#"33", [(#"", 1), (#"33", 1)])]) + flatten(v) == [(#"33", #"", 1), (#"33", #"33", 1)] +} + +test from_asset_list_6() fail { + let v = + from_asset_list( + [(#"33", [(#"", 1), (#"33", 1)]), (#"33", [(#"", 1), (#"33", 1)])], + ) + flatten(v) == [(#"33", #"", 1), (#"33", #"33", 1)] +} + +test from_asset_list_7() fail { + let v = + from_asset_list( + [(#"33", [(#"", 1), (#"33", 1)]), (#"34", [(#"", 1), (#"", 1)])], + ) + flatten(v) == [(#"33", #"", 1), (#"33", #"33", 1), (#"34", #"", 1)] +} + +test from_asset_list_8() { + let v = + from_asset_list( + [ + (#"33", [(#"", 1), (#"33", 1)]), + (#"34", [(#"31", 1)]), + (#"35", [(#"", 1)]), + ], + ) + flatten(v) == [ + (#"33", #"", 1), + (#"33", #"33", 1), + (#"34", #"31", 1), + (#"35", #"", 1), + ] +} + /// Convert the value into a dictionary of dictionaries. pub fn to_dict(self: Value) -> Dict> { self.inner @@ -454,11 +534,13 @@ pub fn from_minted_value(self: MintedValue) -> Value { } test from_minted_value_1() { - flatten(from_minted_value(from_list([]))) == [] + flatten(from_minted_value(from_internal_list([]))) == [] } test from_minted_value_2() { - flatten(from_minted_value(from_list([("p0", "a0", 1)]))) == [("p0", "a0", 1)] + flatten(from_minted_value(from_internal_list([("p0", "a0", 1)]))) == [ + ("p0", "a0", 1), + ] } test from_minted_value_3() { @@ -468,7 +550,7 @@ test from_minted_value_3() { let result = [("p0", "a0", 2), ("p1", "a0", 1), ("p1", "a1", 1)] - flatten(from_minted_value(from_list(assets))) == result + flatten(from_minted_value(from_internal_list(assets))) == result } test from_minted_value_4() { @@ -484,7 +566,7 @@ test from_minted_value_4() { let result = [("p0", "a0", 2), ("p1", "a0", 1), ("p1", "a1", 1)] - flatten(from_minted_value(from_list(assets))) == result + flatten(from_minted_value(from_internal_list(assets))) == result } test from_minted_value_5() { @@ -507,17 +589,17 @@ test from_minted_value_5() { ("p3", "a7", 1), ] - flatten(from_minted_value(from_list(assets))) == assets + flatten(from_minted_value(from_internal_list(assets))) == assets } /// Convert a [`Value`](#Value) into a [`MintedValue`](#MintedValue). pub fn to_minted_value(self: Value) -> MintedValue { self.inner |> dict.insert( - ada_policy_id, - dict.insert(dict.new(), ada_asset_name, 0, bytearray.compare), - bytearray.compare, - ) + ada_policy_id, + dict.insert(dict.new(), ada_asset_name, 0, bytearray.compare), + bytearray.compare, + ) |> MintedValue } @@ -539,7 +621,7 @@ test to_minted_value_2() { /// /// NOTE: Not exposed because we do not want people to construct `MintedValue`. Only /// get them from the script context. -fn from_list(xs: List<(PolicyId, AssetName, Int)>) -> MintedValue { +fn from_internal_list(xs: List<(PolicyId, AssetName, Int)>) -> MintedValue { list.foldr( xs, MintedValue(dict.new()), From e4758166ca52bd297d9899ad755330c53a573d14 Mon Sep 17 00:00:00 2001 From: microproofs Date: Sun, 24 Mar 2024 13:59:14 -0400 Subject: [PATCH 20/45] update aiken version --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index f88177b..4f51695 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -33,7 +33,7 @@ jobs: - name: 🧰 Install Aiken uses: aiken-lang/setup-aiken@v0.1.0 with: - version: v1.0.24-alpha + version: v1.0.25-alpha - name: 📝 Run fmt run: aiken fmt --check From d9655fc137c7663f575715ebeae1cff09535fb83 Mon Sep 17 00:00:00 2001 From: microproofs Date: Wed, 27 Mar 2024 11:57:03 -0400 Subject: [PATCH 21/45] fix formatting and update workflow version --- .github/workflows/continuous-integration.yml | 2 +- lib/aiken/cbor.ak | 6 +-- lib/aiken/int.ak | 40 +++++++------- lib/aiken/math/rational.ak | 12 ++--- lib/aiken/transaction.ak | 56 ++++++++++---------- 5 files changed, 58 insertions(+), 58 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 4f51695..12e257f 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -33,7 +33,7 @@ jobs: - name: 🧰 Install Aiken uses: aiken-lang/setup-aiken@v0.1.0 with: - version: v1.0.25-alpha + version: v1.0.26-alpha - name: 📝 Run fmt run: aiken fmt --check diff --git a/lib/aiken/cbor.ak b/lib/aiken/cbor.ak index 7f0db02..7de71e7 100644 --- a/lib/aiken/cbor.ak +++ b/lib/aiken/cbor.ak @@ -201,9 +201,9 @@ fn do_diagnostic(self: Data, builder: ByteArray) -> ByteArray { bytes |> encode_base16( - length_of_bytearray(bytes) - 1, - append_bytearray(#"27", builder), - ) + length_of_bytearray(bytes) - 1, + append_bytearray(#"27", builder), + ) |> append_bytearray(#"6827", _) }, ) diff --git a/lib/aiken/int.ak b/lib/aiken/int.ak index b0e7524..fd602b6 100644 --- a/lib/aiken/int.ak +++ b/lib/aiken/int.ak @@ -32,26 +32,26 @@ pub fn compare(left: Int, right: Int) -> Ordering { pub fn from_utf8(bytes: ByteArray) -> Option { bytes |> bytearray.foldr( - Some((0, 0)), - fn(byte, st) { - when st is { - None -> None - Some((n, e)) -> - if byte < 48 || byte > 57 { - if byte == 45 { - Some((-n, 0)) - } else { - None - } - } else if n < 0 { - None - } else { - let digit = byte - 48 - Some((n + digit * math.pow(10, e), e + 1)) - } - } - }, - ) + Some((0, 0)), + fn(byte, st) { + when st is { + None -> None + Some((n, e)) -> + if byte < 48 || byte > 57 { + if byte == 45 { + Some((-n, 0)) + } else { + None + } + } else if n < 0 { + None + } else { + let digit = byte - 48 + Some((n + digit * math.pow(10, e), e + 1)) + } + } + }, + ) |> option.map(fn(tuple) { tuple.1st }) } diff --git a/lib/aiken/math/rational.ak b/lib/aiken/math/rational.ak index 6e0ec04..e62a65d 100644 --- a/lib/aiken/math/rational.ak +++ b/lib/aiken/math/rational.ak @@ -644,7 +644,7 @@ test compare_with_eq() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - !eq(x, y)? && ( !eq(y, x)? && eq(x, x)? ) + !eq(x, y)? && !eq(y, x)? && eq(x, x)? } test compare_with_neq() { @@ -654,7 +654,7 @@ test compare_with_neq() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - neq(x, y)? && ( neq(y, x)? && !neq(x, x)? ) + neq(x, y)? && neq(y, x)? && !neq(x, x)? } test compare_with_gte() { @@ -664,7 +664,7 @@ test compare_with_gte() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - !gte(x, y)? && ( gte(y, x)? && gte(x, x)? ) + !gte(x, y)? && gte(y, x)? && gte(x, x)? } test compare_with_gt() { @@ -674,7 +674,7 @@ test compare_with_gt() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - !gt(x, y)? && ( gt(y, x)? && !gt(x, x)? ) + !gt(x, y)? && gt(y, x)? && !gt(x, x)? } test compare_with_lte() { @@ -684,7 +684,7 @@ test compare_with_lte() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - lte(x, y)? && ( !lte(y, x)? && lte(x, x)? ) + lte(x, y)? && !lte(y, x)? && lte(x, x)? } test compare_with_lt() { @@ -694,7 +694,7 @@ test compare_with_lt() { expect Some(x) = new(2, 3) expect Some(y) = new(3, 4) - lt(x, y)? && ( !lt(y, x)? && !lt(x, x)? ) + lt(x, y)? && !lt(y, x)? && !lt(x, x)? } /// Calculate the arithmetic mean between two `Rational` values. diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index 6b3cbb1..fb020ed 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -183,26 +183,26 @@ pub fn find_datum( datums |> dict.get(datum_hash) |> option.or_try( - fn() { - outputs - |> list.filter_map( - fn(output) { - when output.datum is { - InlineDatum(data) -> - if - blake2b_256(builtin.serialise_data(data)) == datum_hash{ - - Some(data) - } else { - None - } - _ -> None - } - }, - ) - |> list.head - }, - ) + fn() { + outputs + |> list.filter_map( + fn(output) { + when output.datum is { + InlineDatum(data) -> + if + blake2b_256(builtin.serialise_data(data)) == datum_hash{ + + Some(data) + } else { + None + } + _ -> None + } + }, + ) + |> list.head + }, + ) } /// Find all outputs that are paying into the given script hash, if any. This is useful for @@ -213,12 +213,12 @@ pub fn find_script_outputs( ) -> List { outputs |> list.filter( - fn(output) { - when output.address.payment_credential is { - ScriptCredential(addr_script_hash) -> - script_hash == addr_script_hash - VerificationKeyCredential(_) -> False - } - }, - ) + fn(output) { + when output.address.payment_credential is { + ScriptCredential(addr_script_hash) -> + script_hash == addr_script_hash + VerificationKeyCredential(_) -> False + } + }, + ) } From 7795b24cc92565fd5152900974576cf8bbafd839 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 28 Mar 2024 09:25:52 +0100 Subject: [PATCH 22/45] Add explainer to from_asset_list and one extra test That last test show that we actually can provide policy ids out of order. --- lib/aiken/transaction/value.ak | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 8f0fcb9..5ea4b97 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -431,6 +431,16 @@ test reduce_3() { result == 1 } +/// Promote an arbitrary list of assets into a `Value`. This function fails +/// (i.e. halt the program execution) if: +/// +/// - there's any duplicate amongst `PolicyId`; +/// - there's any duplicate amongst `AssetName`; +/// - the `AssetName` aren't sorted in ascending lexicographic order; or +/// - any asset quantity is null. +/// +/// This function is meant to turn arbitrary user-defined `Data` into safe `Value`, +/// while checking for internal invariants. pub fn from_asset_list(xs: List<(PolicyId, List<(AssetName, Int)>)>) -> Value { xs |> list.foldr( @@ -465,7 +475,7 @@ test from_asset_list_2() fail { test from_asset_list_3() fail { let v = from_asset_list([(#"33", [(#"", 0)])]) - v == zero() + v != zero() } test from_asset_list_4() { @@ -483,7 +493,7 @@ test from_asset_list_6() fail { from_asset_list( [(#"33", [(#"", 1), (#"33", 1)]), (#"33", [(#"", 1), (#"33", 1)])], ) - flatten(v) == [(#"33", #"", 1), (#"33", #"33", 1)] + v != zero() } test from_asset_list_7() fail { @@ -491,7 +501,7 @@ test from_asset_list_7() fail { from_asset_list( [(#"33", [(#"", 1), (#"33", 1)]), (#"34", [(#"", 1), (#"", 1)])], ) - flatten(v) == [(#"33", #"", 1), (#"33", #"33", 1), (#"34", #"", 1)] + v != zero() } test from_asset_list_8() { @@ -511,6 +521,23 @@ test from_asset_list_8() { ] } +test from_asset_list_9() { + let v = + from_asset_list( + [ + (#"35", [(#"", 1)]), + (#"33", [(#"", 1), (#"33", 1)]), + (#"34", [(#"31", 1)]), + ], + ) + flatten(v) == [ + (#"33", #"", 1), + (#"33", #"33", 1), + (#"34", #"31", 1), + (#"35", #"", 1), + ] +} + /// Convert the value into a dictionary of dictionaries. pub fn to_dict(self: Value) -> Dict> { self.inner From c074d343e869b380861b0fc834944c3cefbca982 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 28 Mar 2024 09:26:05 +0100 Subject: [PATCH 23/45] Fill-in CHANGELOG for 1.8.0 --- CHANGELOG.md | 18 ++++++++++++++++++ aiken.toml | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a32aaf9..d67ad5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## v1.8.0 - 2024-03-28 + +### Added + +- [`value.reduce`](https://aiken-lang.github.io/stdlib/aiken/transaction/value.html#reduce) to efficiently fold over a value and its elements. + +- [`value.from_asset_list`](https://aiken-lang.github.io/stdlib/aiken/transaction/value.html#from_asset_list) to turn an asset list into a Value while enforcing invariants expected of `Value`. + +- [`math.is_sqrt`](https://aiken-lang.github.io/stdlib/aiken/math.html#is_sqrt) as a more efficient alternative to `sqrt`. + +### Changed + +- Disclaimers in documentation to [`bytearray.to_string`](https://aiken-lang.github.io/stdlib/aiken/bytearray.html#to_string) and [`string.from_bytearray`](https://aiken-lang.github.io/stdlib/aiken/string.html#from_bytearray) regarding UTF-8 encoding. + +### Removed + +N/A + ## v1.7.0 - 2023-11-07 ### Added diff --git a/aiken.toml b/aiken.toml index b830018..af339e7 100644 --- a/aiken.toml +++ b/aiken.toml @@ -1,5 +1,5 @@ name = "aiken-lang/stdlib" -version = "1.7.0" +version = "1.8.0" licences = ["Apache-2.0"] description = "The Aiken Standard Library" From be9303939d1f5290f57bcfd665fa2ea116142b61 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 28 Mar 2024 09:36:06 +0100 Subject: [PATCH 24/45] Fix link in string.from_bytearray disclaimer. --- lib/aiken/string.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/string.ak b/lib/aiken/string.ak index 11d7179..b9eee08 100644 --- a/lib/aiken/string.ak +++ b/lib/aiken/string.ak @@ -26,7 +26,7 @@ test concat_3() { /// Convert a `ByteArray` into a `String` /// -///
⚠️
WARNING
| This functions fails if the underlying `ByteArray` isn't UTF-8-encoded.
In particular, you cannot convert arbitrary hash digests using this function.
For converting arbitrary `ByteArray`s, use [bytearray.to_hex](../bytearray.html#to_hex). +///
⚠️
WARNING
| This functions fails if the underlying `ByteArray` isn't UTF-8-encoded.
In particular, you cannot convert arbitrary hash digests using this function.
For converting arbitrary `ByteArray`s, use [bytearray.to_hex](/stdlib/aiken/bytearray.html#to_hex). /// --- | --- /// /// ```aiken From f02446f00bb265039ea39446a3b503b10dfd38a3 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sun, 14 Jan 2024 17:30:01 +0100 Subject: [PATCH 25/45] Specialize Dict's key to ByteArray Looking at Aiken's repositories in the wild, no one is using Dict with anything else than ByteArray as key. The extra complexity we bring just for making it generic in the key argument seems not worth it. Plus, if we know the key is a ByteArray, we can perform some optimizations on a few functions looking for keys to short-circuit them instead of traversing a list entirely. Here's a comparison of the mem and cpu cost before and after the chance for a few tests (omitted tests have identical cost). | mem | cpu | bench | | --- | --- | --- | | -10.15% | -5.88% | delete_3 | | -4.00% | -9.68% | delete_4 | | -3.80% | -9.39% | delete_5 | | -31.03% | -42.88% | delete_6 | | -15.26% | -26.34% | find_4 | | -11.10% | -18.85% | from_list_2 | | -8.02% | -16.26% | from_list_3 | | -12.15% | -25.39% | from_list_4 | | -19.24% | -36.11% | bench_from_list | | -17.79% | -18.91% | bench_from_ascending_list | | -4.91% | -10.58% | get_2 | | -9.49% | -14.63% | get_3 | | -29.94% | -42.75% | get_4 | | -23.66% | -37.70% | get_5 | | -7.94% | -5.03% | has_key_3 | | -9.97% | -18.50% | has_key_4 | | -16.46% | -23.61% | insert_1 | | -16.52% | -26.24% | insert_2 | | -13.82% | -22.08% | insert_with_1 | | -18.77% | -29.88% | insert_with_2 | | -19.12% | -30.52% | insert_with_3 | | -10.47% | -17.40% | keys_2 | | 4.25% | 5.06% | map_1 | | 2.94% | 3.31% | map_2 | | -10.99% | -19.83% | size_3 | | -7.94% | -16.17% | union_1 | | -17.74% | -28.17% | union_3 | | -16.96% | -26.55% | union_4 | | -15.91% | -25.10% | union_with_1 | | -10.47% | -17.39% | values_2 | --- CHANGELOG.md | 14 + lib/aiken/dict.ak | 560 +++++++++++++++------------------ lib/aiken/transaction/value.ak | 21 +- 3 files changed, 280 insertions(+), 315 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d67ad5e..c1e6363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## UNRELEASED + +### Added + +N/A + +### Changed + +- Specialized all `Dict`'s key as `ByteArray`, and thus remove the need for passing an extra comparison function. + +### Removed + +N/A + ## v1.8.0 - 2024-03-28 ### Added diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index 7507362..fab5a41 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -4,7 +4,7 @@ //// which preserve some invariants. In particular, each key is only present //// once in the dictionary. -use aiken/bytearray +use aiken/builtin /// An opaque `Dict`. The type is opaque because the module maintains some /// invariant, namely: there's only one occurrence of a given key in the dictionary. @@ -20,7 +20,7 @@ use aiken/bytearray /// Dict> /// ``` pub opaque type Dict { - inner: List<(key, value)>, + inner: List<(ByteArray, value)>, } /// Create a new map @@ -39,35 +39,40 @@ const baz = #"62617a" fn fixture_1() { new() - |> insert(foo, 42, bytearray.compare) - |> insert(bar, 14, bytearray.compare) + |> insert(foo, 42) + |> insert(bar, 14) } /// Remove a key-value pair from the dictionary. If the key is not found, no changes are made. /// /// ```aiken -/// use aiken/int -/// /// let result = /// dict.new() -/// |> dict.insert(key: 1, value: 100, compare: int.compare) -/// |> dict.insert(key: 2, value: 200, compare: int.compare) -/// |> dict.delete(key: 1) +/// |> dict.insert(key: "a", value: 100) +/// |> dict.insert(key: "b", value: 200) +/// |> dict.delete(key: "a") /// |> dict.to_list() /// -/// result == [(2, 200)] +/// result == [("b", 200)] /// ``` -pub fn delete(self: Dict, key: key) -> Dict { +pub fn delete(self: Dict, key: ByteArray) -> Dict { Dict { inner: do_delete(self.inner, key) } } -fn do_delete(self: List<(key, value)>, key k: key) -> List<(key, value)> { +fn do_delete( + self: List<(ByteArray, value)>, + key k: ByteArray, +) -> List<(ByteArray, value)> { when self is { [] -> [] [(k2, v2), ..rest] -> - if k == k2 { - rest + if builtin.less_than_equals_bytearray(k, k2) { + if k == k2 { + rest + } else { + self + } } else { [(k2, v2), ..do_delete(rest, k)] } @@ -81,59 +86,74 @@ test delete_1() { test delete_2() { let m = new() - |> insert(foo, 14, bytearray.compare) + |> insert(foo, 14) delete(m, foo) == new() } test delete_3() { let m = new() - |> insert(foo, 14, bytearray.compare) + |> insert(foo, 14) delete(m, bar) == m } test delete_4() { let m = new() - |> insert(foo, 14, bytearray.compare) - |> insert(bar, 14, bytearray.compare) + |> insert(foo, 14) + |> insert(bar, 14) !has_key(delete(m, foo), foo) } test delete_5() { let m = new() - |> insert(foo, 14, bytearray.compare) - |> insert(bar, 14, bytearray.compare) + |> insert(foo, 14) + |> insert(bar, 14) has_key(delete(m, bar), foo) } +test delete_6() { + let m = + new() + |> insert("aaa", 1) + |> insert("bbb", 2) + |> insert("ccc", 3) + |> insert("ddd", 4) + |> insert("eee", 5) + |> insert("fff", 6) + |> insert("ggg", 7) + |> insert("hhh", 8) + |> insert("iii", 9) + |> insert("jjj", 10) + + delete(m, "bcd") == m +} + /// Keep only the key-value pairs that pass the given predicate. /// /// ```aiken -/// use aiken/int -/// /// let result = /// dict.new() -/// |> dict.insert(key: 1, value: 100, compare: int.compare) -/// |> dict.insert(key: 2, value: 200, compare: int.compare) -/// |> dict.insert(key: 3, value: 300, compare: int.compare) -/// |> dict.filter(fn(k, _v) { k > 1 }) +/// |> dict.insert(key: "a", value: 100) +/// |> dict.insert(key: "b", value: 200) +/// |> dict.insert(key: "c", value: 300) +/// |> dict.filter(fn(k, _v) { k != "a" }) /// |> dict.to_list() /// -/// result == [(2, 200), (3, 300)] +/// result == [("b", 200), ("c", 300)] /// ``` pub fn filter( self: Dict, - with: fn(key, value) -> Bool, + with: fn(ByteArray, value) -> Bool, ) -> Dict { Dict { inner: do_filter(self.inner, with) } } fn do_filter( - self: List<(key, value)>, - with: fn(key, value) -> Bool, -) -> List<(key, value)> { + self: List<(ByteArray, value)>, + with: fn(ByteArray, value) -> Bool, +) -> List<(ByteArray, value)> { when self is { [] -> [] @@ -153,40 +173,34 @@ test filter_1() { test filter_2() { let expected = new() - |> insert(foo, 42, bytearray.compare) + |> insert(foo, 42) filter(fixture_1(), fn(_, v) { v > 14 }) == expected } test filter_3() { let expected = new() - |> insert(bar, 14, bytearray.compare) + |> insert(bar, 14) filter(fixture_1(), fn(k, _) { k == bar }) == expected } /// Finds a value in the dictionary, and returns the first key found to have that value. /// /// ```aiken -/// use aiken/bytearray -/// -/// let foo: ByteArray = #"00" -/// let bar: ByteArray = #"11" -/// let baz: ByteArray = #"22" -/// /// let result = /// dict.new() -/// |> dict.insert(key: foo, value: 42, compare: bytearray.compare) -/// |> dict.insert(key: bar, value: 14, compare: bytearray.compare) -/// |> dict.insert(key: baz, value: 42, compare: bytearray.compare) +/// |> dict.insert(key: "a", value: 42) +/// |> dict.insert(key: "b", value: 14) +/// |> dict.insert(key: "c", value: 42) /// |> dict.find(42) /// -/// result == Some(foo) +/// result == Some("c") /// ``` -pub fn find(self: Dict, value v: value) -> Option { +pub fn find(self: Dict, value v: value) -> Option { do_find(self.inner, v) } -fn do_find(self: List<(key, value)>, value v: value) -> Option { +fn do_find(self: List<(ByteArray, value)>, value v: value) -> Option { when self is { [] -> None [(k2, v2), ..rest] -> @@ -205,7 +219,7 @@ test find_1() { test find_2() { find( new() - |> insert(foo, 14, bytearray.compare), + |> insert(foo, 14), 14, ) == Some(foo) } @@ -213,7 +227,7 @@ test find_2() { test find_3() { find( new() - |> insert(foo, 14, bytearray.compare), + |> insert(foo, 14), 42, ) == None } @@ -221,9 +235,9 @@ test find_3() { test find_4() { find( new() - |> insert(foo, 14, bytearray.compare) - |> insert(bar, 42, bytearray.compare) - |> insert(baz, 14, bytearray.compare), + |> insert(foo, 14) + |> insert(bar, 42) + |> insert(baz, 14), 14, ) == Some(baz) } @@ -232,13 +246,11 @@ test find_4() { /// in ascending order and is done from right-to-left. /// /// ```aiken -/// use aiken/int -/// /// let result = /// dict.new() -/// |> dict.insert(key: 1, value: 100, compare: int.compare) -/// |> dict.insert(key: 2, value: 200, compare: int.compare) -/// |> dict.insert(key: 3, value: 300, compare: int.compare) +/// |> dict.insert(key: "a", value: 100) +/// |> dict.insert(key: "b", value: 200) +/// |> dict.insert(key: "c", value: 300) /// |> dict.foldr(0, fn(_k, v, r) { v + r }) /// /// result == 600 @@ -246,15 +258,15 @@ test find_4() { pub fn foldr( self: Dict, zero: result, - with: fn(key, value, result) -> result, + with: fn(ByteArray, value, result) -> result, ) -> result { do_foldr(self.inner, zero, with) } fn do_foldr( - self: List<(key, value)>, + self: List<(ByteArray, value)>, zero: result, - with: fn(key, value, result) -> result, + with: fn(ByteArray, value, result) -> result, ) -> result { when self is { [] -> zero @@ -274,13 +286,11 @@ test foldr_2() { /// in ascending order and is done from left-to-right. /// /// ```aiken -/// use aiken/int -/// /// let result = /// dict.new() -/// |> dict.insert(key: 1, value: 100, compare: int.compare) -/// |> dict.insert(key: 2, value: 200, compare: int.compare) -/// |> dict.insert(key: 3, value: 300, compare: int.compare) +/// |> dict.insert(key: "a", value: 100) +/// |> dict.insert(key: "b", value: 200) +/// |> dict.insert(key: "c", value: 300) /// |> dict.foldl(0, fn(_k, v, r) { v + r }) /// /// result == 600 @@ -288,15 +298,15 @@ test foldr_2() { pub fn foldl( self: Dict, zero: result, - with: fn(key, value, result) -> result, + with: fn(ByteArray, value, result) -> result, ) -> result { do_foldl(self.inner, zero, with) } fn do_foldl( - self: List<(key, value)>, + self: List<(ByteArray, value)>, zero: result, - with: fn(key, value, result) -> result, + with: fn(ByteArray, value, result) -> result, ) -> result { when self is { [] -> zero @@ -316,51 +326,40 @@ test fold_2() { /// multiple times, the first occurrence prevails. /// /// ```aiken -/// use aiken/int -/// -/// let list = [(1, 100), (3, 300), (2, 200)] +/// let list = [("a", 100), ("c", 300), ("b", 200)] /// /// let result = -/// dict.from_list(list, int.compare) +/// dict.from_list(list) /// |> dict.to_list() /// -/// result == [(1, 100), (2, 200), (3, 300)] +/// result == [("a", 100), ("b", 200), ("c", 300)] /// ``` -pub fn from_list( - self: List<(key, value)>, - compare: fn(key, key) -> Ordering, -) -> Dict { - Dict { inner: do_from_list(self, compare) } +pub fn from_list(self: List<(ByteArray, value)>) -> Dict { + Dict { inner: do_from_list(self) } } -fn do_from_list( - xs: List<(key, value)>, - compare: fn(key, key) -> Ordering, -) -> List<(key, value)> { +fn do_from_list(xs: List<(ByteArray, value)>) -> List<(ByteArray, value)> { when xs is { [] -> [] - [(k, v), ..rest] -> do_insert(do_from_list(rest, compare), k, v, compare) + [(k, v), ..rest] -> do_insert(do_from_list(rest), k, v) } } test from_list_1() { - from_list([], bytearray.compare) == new() + from_list([]) == new() } test from_list_2() { - from_list([(foo, 42), (bar, 14)], bytearray.compare) == from_list( - [(bar, 14), (foo, 42)], - bytearray.compare, - ) + from_list([(foo, 42), (bar, 14)]) == from_list([(bar, 14), (foo, 42)]) } test from_list_3() { - from_list([(foo, 42), (bar, 14)], bytearray.compare) == fixture_1() + from_list([(foo, 42), (bar, 14)]) == fixture_1() } test from_list_4() { - from_list([(foo, 42), (bar, 14), (foo, 1337)], bytearray.compare) == fixture_1() + from_list([(foo, 42), (bar, 14), (foo, 1337)]) == fixture_1() } test bench_from_list() { @@ -384,7 +383,6 @@ test bench_from_list() { ("abbb", 14), ("abba", 6), ], - bytearray.compare, ) size(dict) == 16 @@ -395,40 +393,33 @@ test bench_from_list() { /// sorted. /// /// ```aiken -/// use aiken/int -/// -/// let list = [(1, 100), (2, 200), (3, 300)] +/// let list = [("a", 100), ("b", 200), ("c", 300)] /// /// let result = -/// dict.from_ascending_list(list, int.compare) +/// dict.from_ascending_list(list) /// |> dict.to_list() /// -/// result == [(1, 100), (2, 200), (3, 300)] +/// result == [("a", 100), ("b", 200), ("c", 300)] /// ``` /// /// This is meant to be used to turn a list constructed off-chain into a `Dict` /// which has taken care of maintaining interval invariants. This function still /// performs a sanity check on all keys to avoid silly mistakes. It is, however, /// considerably faster than ['from_list'](from_list) -pub fn from_ascending_list( - xs: List<(key, value)>, - compare: fn(key, key) -> Ordering, -) -> Dict { - let Void = check_ascending_list(xs, compare) +pub fn from_ascending_list(xs: List<(ByteArray, value)>) -> Dict { + let Void = check_ascending_list(xs) Dict { inner: xs } } -fn check_ascending_list( - xs: List<(key, value)>, - compare: fn(key, key) -> Ordering, -) { +fn check_ascending_list(xs: List<(ByteArray, value)>) { when xs is { [] -> Void [_] -> Void [(x0, _), (x1, _) as e, ..rest] -> - when compare(x0, x1) is { - Less -> check_ascending_list([e, ..rest], compare) - _ -> fail @"keys in associative list aren't in ascending order" + if builtin.less_than_bytearray(x0, x1) { + check_ascending_list([e, ..rest]) + } else { + fail @"keys in associative list aren't in ascending order" } } } @@ -489,7 +480,6 @@ test bench_from_ascending_list() { ("bbba", 8), ("bbbb", 16), ], - bytearray.compare, ) size(dict) == 16 @@ -498,27 +488,27 @@ test bench_from_ascending_list() { /// Get a value in the dict by its key. /// /// ```aiken -/// use aiken/bytearray -/// -/// let foo: ByteArray = #"00" -/// /// let result = /// dict.new() -/// |> dict.insert(key: foo, value: "Aiken", compare: bytearray.compare) -/// |> dict.get(key: foo) +/// |> dict.insert(key: "a", value: "Aiken") +/// |> dict.get(key: "a") /// /// result == Some("Aiken") /// ``` -pub fn get(self: Dict, key: key) -> Option { +pub fn get(self: Dict, key: ByteArray) -> Option { do_get(self.inner, key) } -fn do_get(self: List<(key, value)>, key k: key) -> Option { +fn do_get(self: List<(ByteArray, value)>, key k: ByteArray) -> Option { when self is { [] -> None [(k2, v), ..rest] -> - if k == k2 { - Some(v) + if builtin.less_than_equals_bytearray(k, k2) { + if k == k2 { + Some(v) + } else { + None + } } else { do_get(rest, k) } @@ -532,43 +522,73 @@ test get_1() { test get_2() { let m = new() - |> insert(foo, "Aiken", bytearray.compare) - |> insert(bar, "awesome", bytearray.compare) + |> insert(foo, "Aiken") + |> insert(bar, "awesome") get(m, key: foo) == Some("Aiken") } test get_3() { let m = new() - |> insert(foo, "Aiken", bytearray.compare) - |> insert(bar, "awesome", bytearray.compare) + |> insert(foo, "Aiken") + |> insert(bar, "awesome") get(m, key: baz) == None } +test get_4() { + let m = + new() + |> insert("aaa", "1") + |> insert("bbb", "2") + |> insert("ccc", "3") + |> insert("ddd", "4") + |> insert("eee", "5") + |> insert("fff", "6") + |> insert("ggg", "7") + |> insert("hhh", "8") + |> insert("iii", "9") + |> insert("jjj", "10") + + get(m, "bcd") == None +} + +test get_5() { + let m = + new() + |> insert("aaa", "1") + |> insert("bbb", "2") + |> insert("ccc", "3") + |> insert("ddd", "4") + |> insert("eee", "5") + |> insert("fff", "6") + |> insert("ggg", "7") + |> insert("hhh", "8") + |> insert("iii", "9") + |> insert("jjj", "10") + + get(m, "kkk") == None +} + /// Check if a key exists in the dictionary. /// /// ```aiken -/// use aiken/bytearray -/// -/// let foo: ByteArray = #"00" -/// /// let result = /// dict.new() -/// |> dict.insert(key: foo, value: "Aiken", compare: bytearray.compare) -/// |> dict.has_key(foo) +/// |> dict.insert(key: "a", value: "Aiken") +/// |> dict.has_key("a") /// /// result == True /// ``` -pub fn has_key(self: Dict, key k: key) -> Bool { +pub fn has_key(self: Dict, key k: ByteArray) -> Bool { do_has_key(self.inner, k) } -fn do_has_key(self: List<(key, value)>, key k: key) -> Bool { +fn do_has_key(self: List<(ByteArray, value)>, key k: ByteArray) -> Bool { when self is { [] -> False [(k2, _), ..rest] -> - if k == k2 { - True + if builtin.less_than_equals_bytearray(k, k2) { + k == k2 } else { do_has_key(rest, k) } @@ -582,7 +602,7 @@ test has_key_1() { test has_key_2() { has_key( new() - |> insert(foo, 14, bytearray.compare), + |> insert(foo, 14), foo, ) } @@ -590,7 +610,7 @@ test has_key_2() { test has_key_3() { !has_key( new() - |> insert(foo, 14, bytearray.compare), + |> insert(foo, 14), bar, ) } @@ -598,8 +618,8 @@ test has_key_3() { test has_key_4() { has_key( new() - |> insert(foo, 14, bytearray.compare) - |> insert(bar, 42, bytearray.compare), + |> insert(foo, 14) + |> insert(bar, 42), bar, ) } @@ -607,43 +627,39 @@ test has_key_4() { /// Insert a value in the dictionary at a given key. If the key already exists, its value is **overridden**. If you need ways to combine keys together, use (`insert_with`)[#insert_with]. /// /// ```aiken -/// use aiken/bytearray -/// /// let result = /// dict.new() -/// |> dict.insert(key: "foo", value: 1, compare: bytearray.compare) -/// |> dict.insert(key: "bar", value: 2, compare: bytearray.compare) -/// |> dict.insert(key: "foo", value: 3, compare: bytearray.compare) +/// |> dict.insert(key: "a", value: 1) +/// |> dict.insert(key: "b", value: 2) +/// |> dict.insert(key: "a", value: 3) /// |> dict.to_list() /// -/// result == [("bar", 2), ("foo", 3)] +/// result == [("a", 3), ("b", 2)] /// ``` pub fn insert( self: Dict, - key k: key, + key k: ByteArray, value v: value, - compare: fn(key, key) -> Ordering, ) -> Dict { - Dict { inner: do_insert(self.inner, k, v, compare) } + Dict { inner: do_insert(self.inner, k, v) } } fn do_insert( - self: List<(key, value)>, - key k: key, + self: List<(ByteArray, value)>, + key k: ByteArray, value v: value, - compare: fn(key, key) -> Ordering, -) -> List<(key, value)> { +) -> List<(ByteArray, value)> { when self is { [] -> [(k, v)] [(k2, v2), ..rest] -> - if compare(k, k2) == Less { + if builtin.less_than_bytearray(k, k2) { [(k, v), ..self] } else { if k == k2 { [(k, v), ..rest] } else { - [(k2, v2), ..do_insert(rest, k, v, compare)] + [(k2, v2), ..do_insert(rest, k, v)] } } } @@ -652,61 +668,47 @@ fn do_insert( test insert_1() { let m1 = new() - |> insert(foo, 42, bytearray.compare) + |> insert(foo, 42) let m2 = new() - |> insert(foo, 14, bytearray.compare) - insert(m1, foo, 14, bytearray.compare) == m2 + |> insert(foo, 14) + insert(m1, foo, 14) == m2 } test insert_2() { let m1 = new() - |> insert(foo, 42, bytearray.compare) + |> insert(foo, 42) let m2 = new() - |> insert(bar, 14, bytearray.compare) - insert(m1, bar, 14, bytearray.compare) == insert( - m2, - foo, - 42, - bytearray.compare, - ) + |> insert(bar, 14) + insert(m1, bar, 14) == insert(m2, foo, 42) } /// Insert a value in the dictionary at a given key. When the key already exist, the provided /// merge function is called. /// /// ```aiken -/// use aiken/bytearray -/// /// let sum = /// fn (_k, a, b) { Some(a + b) } /// /// let result = /// dict.new() -/// |> dict.insert_with(key: "foo", value: 1, with: sum, compare: bytearray.compare) -/// |> dict.insert_with(key: "bar", value: 2, with: sum, compare: bytearray.compare) -/// |> dict.insert_with(key: "foo", value: 3, with: sum, compare: bytearray.compare) +/// |> dict.insert_with(key: "a", value: 1, with: sum) +/// |> dict.insert_with(key: "b", value: 2, with: sum) +/// |> dict.insert_with(key: "a", value: 3, with: sum) /// |> dict.to_list() /// -/// result == [("bar", 2), ("foo", 4)] +/// result == [("a", 4), ("b", 2)] /// ``` pub fn insert_with( self: Dict, - key k: key, + key k: ByteArray, value v: value, - with: fn(key, value, value) -> Option, - compare: fn(key, key) -> Ordering, + with: fn(ByteArray, value, value) -> Option, ) -> Dict { Dict { - inner: do_insert_with( - self.inner, - k, - v, - fn(k, v1, v2) { with(k, v2, v1) }, - compare, - ), + inner: do_insert_with(self.inner, k, v, fn(k, v1, v2) { with(k, v2, v1) }), } } @@ -716,8 +718,8 @@ test insert_with_1() { let result = new() - |> insert_with(key: "foo", value: 1, with: sum, compare: bytearray.compare) - |> insert_with(key: "bar", value: 2, with: sum, compare: bytearray.compare) + |> insert_with(key: "foo", value: 1, with: sum) + |> insert_with(key: "bar", value: 2, with: sum) |> to_list() result == [("bar", 2), ("foo", 1)] @@ -729,9 +731,9 @@ test insert_with_2() { let result = new() - |> insert_with(key: "foo", value: 1, with: sum, compare: bytearray.compare) - |> insert_with(key: "bar", value: 2, with: sum, compare: bytearray.compare) - |> insert_with(key: "foo", value: 3, with: sum, compare: bytearray.compare) + |> insert_with(key: "foo", value: 1, with: sum) + |> insert_with(key: "bar", value: 2, with: sum) + |> insert_with(key: "foo", value: 3, with: sum) |> to_list() result == [("bar", 2), ("foo", 4)] @@ -749,10 +751,10 @@ test insert_with_3() { let result = new() - |> insert_with(key: "foo", value: 1, with: with, compare: bytearray.compare) - |> insert_with(key: "bar", value: 2, with: with, compare: bytearray.compare) - |> insert_with(key: "foo", value: 3, with: with, compare: bytearray.compare) - |> insert_with(key: "bar", value: 4, with: with, compare: bytearray.compare) + |> insert_with(key: "foo", value: 1, with: with) + |> insert_with(key: "bar", value: 2, with: with) + |> insert_with(key: "foo", value: 3, with: with) + |> insert_with(key: "bar", value: 4, with: with) |> to_list() result == [("foo", 1)] @@ -776,25 +778,20 @@ test is_empty_1() { /// Extract all the keys present in a given `Dict`. /// /// ```aiken -/// use aiken/bytearray -/// -/// let foo: ByteArray = #"00" -/// let bar: ByteArray = #"11" -/// /// let result = /// dict.new() -/// |> dict.insert(foo, 14, bytearray.compare) -/// |> dict.insert(bar, 42, bytearray.compare) -/// |> dict.insert(foo, 1337, bytearray.compare) +/// |> dict.insert("a", 14) +/// |> dict.insert("b", 42) +/// |> dict.insert("a", 1337) /// |> dict.keys() /// -/// result == [foo, bar] +/// result == ["a", "b"] /// ``` -pub fn keys(self: Dict) -> List { +pub fn keys(self: Dict) -> List { do_keys(self.inner) } -fn do_keys(self: List<(key, value)>) -> List { +fn do_keys(self: List<(ByteArray, value)>) -> List { when self is { [] -> [] @@ -810,31 +807,32 @@ test keys_1() { test keys_2() { keys( new() - |> insert(foo, 0, bytearray.compare) - |> insert(bar, 0, bytearray.compare), + |> insert(foo, 0) + |> insert(bar, 0), ) == [bar, foo] } /// Apply a function to all key-value pairs in a map. /// /// ```aiken -/// use aiken/int -/// /// let result = /// dict.new() -/// |> dict.insert(1, 100, int.compare) -/// |> dict.insert(2, 200, int.compare) -/// |> dict.insert(3, 300, int.compare) +/// |> dict.insert("a", 100) +/// |> dict.insert("b", 200) +/// |> dict.insert("c", 300) /// |> dict.map(fn(_k, v) { v * 2 }) /// |> dict.to_list() /// -/// result == [(1, 200), (2, 400), (3, 600)] +/// result == [("a", 200), ("b", 400), ("c", 600)] /// ``` -pub fn map(self: Dict, with: fn(key, a) -> b) -> Dict { +pub fn map(self: Dict, with: fn(ByteArray, a) -> b) -> Dict { Dict { inner: do_map(self.inner, with) } } -fn do_map(self: List<(key, a)>, with: fn(key, a) -> b) -> List<(key, b)> { +fn do_map( + self: List<(ByteArray, a)>, + with: fn(ByteArray, a) -> b, +) -> List<(ByteArray, b)> { when self is { [] -> [] @@ -860,18 +858,16 @@ test map_2() { /// Get the inner list holding the dictionary data. /// /// ```aiken -/// use aiken/int -/// /// let result = /// dict.new() -/// |> dict.insert(1, 100, int.compare) -/// |> dict.insert(2, 200, int.compare) -/// |> dict.insert(3, 300, int.compare) +/// |> dict.insert("a", 100) +/// |> dict.insert("b", 200) +/// |> dict.insert("c", 300) /// |> dict.to_list() /// -/// result == [(1, 100), (2, 200), (3, 300)] +/// result == [("a", 100), ("b", 200), ("c", 300)] /// ``` -pub fn to_list(self: Dict) -> List<(key, value)> { +pub fn to_list(self: Dict) -> List<(ByteArray, value)> { self.inner } @@ -886,13 +882,11 @@ test to_list_2() { /// Return the number of key-value pairs in the dictionary. /// /// ```aiken -/// use aiken/int -/// /// let result = /// dict.new() -/// |> dict.insert(1, 100, int.compare) -/// |> dict.insert(2, 200, int.compare) -/// |> dict.insert(3, 300, int.compare) +/// |> dict.insert("a", 100) +/// |> dict.insert("b", 200) +/// |> dict.insert("c", 300) /// |> dict.size() /// /// result == 3 @@ -915,15 +909,15 @@ test size_1() { test size_2() { size( new() - |> insert(foo, 14, bytearray.compare), + |> insert(foo, 14), ) == 1 } test size_3() { size( new() - |> insert(foo, 14, bytearray.compare) - |> insert(bar, 42, bytearray.compare), + |> insert(foo, 14) + |> insert(bar, 42), ) == 2 } @@ -931,69 +925,59 @@ test size_3() { /// right dictionary, values from the left are preferred (i.e. left-biaised). /// /// ```aiken -/// use aiken/int -/// -/// let left_dict = dict.from_list([(1, 100), (2, 200)], int.compare) -/// let right_dict = dict.from_list([(1, 150), (3, 300)], int.compare) +/// let left_dict = dict.from_list([("a", 100), ("b", 200)]) +/// let right_dict = dict.from_list([("a", 150), ("c", 300)]) /// /// let result = -/// dict.union(left_dict, right_dict, int.compare) |> dict.to_list() +/// dict.union(left_dict, right_dict) |> dict.to_list() /// -/// result == [(1, 100), (2, 200), (3, 300)] +/// result == [("a", 100), ("b", 200), ("c", 300)] /// ``` pub fn union( left: Dict, right: Dict, - compare: fn(key, key) -> Ordering, ) -> Dict { - Dict { inner: do_union(left.inner, right.inner, compare) } + Dict { inner: do_union(left.inner, right.inner) } } fn do_union( - left: List<(key, value)>, - right: List<(key, value)>, - compare: fn(key, key) -> Ordering, -) -> List<(key, value)> { + left: List<(ByteArray, value)>, + right: List<(ByteArray, value)>, +) -> List<(ByteArray, value)> { when left is { [] -> right - [(k, v), ..rest] -> do_union(rest, do_insert(right, k, v, compare), compare) + [(k, v), ..rest] -> do_union(rest, do_insert(right, k, v)) } } test union_1() { - union(fixture_1(), new(), bytearray.compare) == fixture_1() + union(fixture_1(), new()) == fixture_1() } test union_2() { - union(new(), fixture_1(), bytearray.compare) == fixture_1() + union(new(), fixture_1()) == fixture_1() } test union_3() { let left = new() - |> insert(foo, 14, bytearray.compare) + |> insert(foo, 14) let right = new() - |> insert(bar, 42, bytearray.compare) - |> insert(baz, 1337, bytearray.compare) - union(left, right, bytearray.compare) == from_list( - [(foo, 14), (baz, 1337), (bar, 42)], - bytearray.compare, - ) + |> insert(bar, 42) + |> insert(baz, 1337) + union(left, right) == from_list([(foo, 14), (baz, 1337), (bar, 42)]) } test union_4() { let left = new() - |> insert(foo, 14, bytearray.compare) + |> insert(foo, 14) let right = new() - |> insert(bar, 42, bytearray.compare) - |> insert(foo, 1337, bytearray.compare) - union(left, right, bytearray.compare) == from_list( - [(foo, 14), (bar, 42)], - bytearray.compare, - ) + |> insert(bar, 42) + |> insert(foo, 1337) + union(left, right) == from_list([(foo, 14), (bar, 42)]) } /// Like [`union`](#union) but allows specifying the behavior to adopt when a key is present @@ -1003,61 +987,50 @@ test union_4() { /// When passing `None`, the value is removed and not present in the union. /// /// ```aiken -/// use aiken/int -/// -/// let left_dict = dict.from_list([(1, 100), (2, 200)], int.compare) -/// let right_dict = dict.from_list([(1, 150), (3, 300)], int.compare) +/// let left_dict = dict.from_list([("a", 100), ("b", 200)]) +/// let right_dict = dict.from_list([("a", 150), ("c", 300)]) /// /// let result = /// dict.union_with( /// left_dict, /// right_dict, /// fn(_k, v1, v2) { Some(v1 + v2) }, -/// int.compare, /// ) /// |> dict.to_list() /// -/// result == [(1, 250), (2, 200), (3, 300)] +/// result == [("a", 250), ("b", 200), ("c", 300)] /// ``` pub fn union_with( left: Dict, right: Dict, - with: fn(key, value, value) -> Option, - compare: fn(key, key) -> Ordering, + with: fn(ByteArray, value, value) -> Option, ) -> Dict { - Dict { inner: do_union_with(left.inner, right.inner, with, compare) } + Dict { inner: do_union_with(left.inner, right.inner, with) } } fn do_union_with( - left: List<(key, value)>, - right: List<(key, value)>, - with: fn(key, value, value) -> Option, - compare: fn(key, key) -> Ordering, -) -> List<(key, value)> { + left: List<(ByteArray, value)>, + right: List<(ByteArray, value)>, + with: fn(ByteArray, value, value) -> Option, +) -> List<(ByteArray, value)> { when left is { [] -> right [(k, v), ..rest] -> - do_union_with( - rest, - do_insert_with(right, k, v, with, compare), - with, - compare, - ) + do_union_with(rest, do_insert_with(right, k, v, with), with) } } fn do_insert_with( - self: List<(key, value)>, - key k: key, + self: List<(ByteArray, value)>, + key k: ByteArray, value v: value, - with: fn(key, value, value) -> Option, - compare: fn(key, key) -> Ordering, -) -> List<(key, value)> { + with: fn(ByteArray, value, value) -> Option, +) -> List<(ByteArray, value)> { when self is { [] -> [(k, v)] [(k2, v2), ..rest] -> - if compare(k, k2) == Less { + if builtin.less_than_bytearray(k, k2) { [(k, v), ..self] } else { if k == k2 { @@ -1067,7 +1040,7 @@ fn do_insert_with( None -> rest } } else { - [(k2, v2), ..do_insert_with(rest, k, v, with, compare)] + [(k2, v2), ..do_insert_with(rest, k, v, with)] } } } @@ -1076,37 +1049,26 @@ fn do_insert_with( test union_with_1() { let left = new() - |> insert(foo, 14, bytearray.compare) + |> insert(foo, 14) let right = new() - |> insert(bar, 42, bytearray.compare) - |> insert(foo, 1337, bytearray.compare) + |> insert(bar, 42) + |> insert(foo, 1337) - let result = - union_with( - left, - right, - with: fn(_, l, r) { Some(l + r) }, - compare: bytearray.compare, - ) + let result = union_with(left, right, with: fn(_, l, r) { Some(l + r) }) - result == from_list([(foo, 1351), (bar, 42)], bytearray.compare) + result == from_list([(foo, 1351), (bar, 42)]) } /// Extract all the values present in a given `Dict`. /// /// ```aiken -/// use aiken/bytearray -/// -/// let foo: ByteArray = #"00" -/// let bar: ByteArray = #"11" -/// /// let result = /// dict.new() -/// |> dict.insert(foo, 14, bytearray.compare) -/// |> dict.insert(bar, 42, bytearray.compare) -/// |> dict.insert(foo, 1337, bytearray.compare) +/// |> dict.insert("a", 14) +/// |> dict.insert("b", 42) +/// |> dict.insert("c", 1337) /// |> dict.values() /// /// result == [1337, 42] @@ -1131,7 +1093,7 @@ test values_1() { test values_2() { values( new() - |> insert(foo, 3, bytearray.compare) - |> insert(bar, 4, bytearray.compare), + |> insert(foo, 3) + |> insert(bar, 4), ) == [4, 3] } diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 5ea4b97..d5a2063 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -1,4 +1,3 @@ -use aiken/bytearray use aiken/dict.{Dict, from_ascending_list_with} use aiken/hash.{Blake2b_224, Hash} use aiken/list @@ -57,9 +56,9 @@ pub fn from_asset( } else { let asset = dict.new() - |> dict.insert(asset_name, quantity, bytearray.compare) + |> dict.insert(asset_name, quantity) dict.new() - |> dict.insert(policy_id, asset, bytearray.compare) + |> dict.insert(policy_id, asset) |> Value } } @@ -129,7 +128,6 @@ pub fn merge(left v0: Value, right v1: Value) -> Value { Some(q) } }, - bytearray.compare, ) if dict.is_empty(result) { None @@ -137,7 +135,6 @@ pub fn merge(left v0: Value, right v1: Value) -> Value { Some(result) } }, - bytearray.compare, ), ) } @@ -221,7 +218,6 @@ pub fn add( Some(q) } }, - bytearray.compare, ) if dict.is_empty(inner_result) { None @@ -234,9 +230,8 @@ pub fn add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_list([(asset_name, quantity)], bytearray.compare), + dict.from_ascending_list([(asset_name, quantity)]), helper, - bytearray.compare, ), ) } @@ -622,11 +617,7 @@ test from_minted_value_5() { /// Convert a [`Value`](#Value) into a [`MintedValue`](#MintedValue). pub fn to_minted_value(self: Value) -> MintedValue { self.inner - |> dict.insert( - ada_policy_id, - dict.insert(dict.new(), ada_asset_name, 0, bytearray.compare), - bytearray.compare, - ) + |> dict.insert(ada_policy_id, dict.insert(dict.new(), ada_asset_name, 0)) |> MintedValue } @@ -669,7 +660,7 @@ fn unchecked_add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_list([(asset_name, quantity)], bytearray.compare), + dict.from_ascending_list([(asset_name, quantity)]), fn(_, left, _right) { Some( dict.insert_with( @@ -677,11 +668,9 @@ fn unchecked_add( asset_name, quantity, fn(_k, ql, qr) { Some(ql + qr) }, - bytearray.compare, ), ) }, - bytearray.compare, ), ) } From 2df2aa8b35d4155c377c725c0476e054ac58f0a0 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 18 Apr 2024 18:57:54 +0200 Subject: [PATCH 26/45] Replace occurences of 2-tuples with pairs --- lib/aiken/cbor.ak | 23 ++- lib/aiken/dict.ak | 332 +++++++++++++++++---------------- lib/aiken/transaction.ak | 10 +- lib/aiken/transaction/value.ak | 45 +++-- 4 files changed, 215 insertions(+), 195 deletions(-) diff --git a/lib/aiken/cbor.ak b/lib/aiken/cbor.ak index 7de71e7..1e5e142 100644 --- a/lib/aiken/cbor.ak +++ b/lib/aiken/cbor.ak @@ -51,7 +51,7 @@ test serialise_5() { } test serialise_6() { - serialise([(1, #"ff")]) == #"a10141ff" + serialise([(1, #"ff")]) == #"9f9f0141ffffff" } test serialise_7() { @@ -62,6 +62,10 @@ test serialise_8() { serialise(None) == #"d87a80" } +test serialise_9() { + serialise([Pair(1, #"ff")]) == #"a10141ff" +} + /// Obtain a String representation of _anything_. This is particularly (and only) useful for tracing /// and debugging. This function is expensive and should not be used in any production code as it /// will very likely explodes the validator's budget. @@ -111,8 +115,7 @@ fn do_diagnostic(self: Data, builder: ByteArray) -> ByteArray { self, { // -------- Constr - - let (constr, fields) = un_constr_data(self) + let Pair(constr, fields) = un_constr_data(self) // NOTE: This is fundamentally the same logic for serializing list. However, the compiler // doesn't support mutual recursion just yet, so we can't extract that logic in a separate @@ -159,7 +162,7 @@ fn do_diagnostic(self: Data, builder: ByteArray) -> ByteArray { list.foldr( elems, (#"207d", builder), - fn(e: (Data, Data), st: (ByteArray, ByteArray)) { + fn(e: Pair, st: (ByteArray, ByteArray)) { let value = do_diagnostic(e.2nd, append_bytearray(st.1st, st.2nd)) ( @@ -285,7 +288,11 @@ test diagnostic_6() { } test diagnostic_7() { - diagnostic([(1, #"ff")]) == @"{_ 1: h'FF' }" + diagnostic([(1, #"ff")]) == @"[_ [_ 1, h'FF']]" +} + +test diagnostic_7_alt() { + diagnostic([Pair(1, #"ff")]) == @"{_ 1: h'FF' }" } test diagnostic_8() { @@ -299,6 +306,12 @@ test diagnostic_9() { test diagnostic_10() { let xs: List<(Int, Int)> = [] + diagnostic(xs) == @"[]" +} + +test diagnostic_10_alt() { + let xs: Map = + [] diagnostic(xs) == @"{}" } diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index fab5a41..3bf918f 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -20,12 +20,12 @@ use aiken/builtin /// Dict> /// ``` pub opaque type Dict { - inner: List<(ByteArray, value)>, + inner: Map, } /// Create a new map /// ```aiken -/// dict.to_list(dict.new()) == [] +/// dict.to_map(dict.new()) == [] /// ``` pub fn new() -> Dict { Dict { inner: [] } @@ -51,22 +51,22 @@ fn fixture_1() { /// |> dict.insert(key: "a", value: 100) /// |> dict.insert(key: "b", value: 200) /// |> dict.delete(key: "a") -/// |> dict.to_list() +/// |> dict.to_map() /// -/// result == [("b", 200)] +/// result == [Pair("b", 200)] /// ``` pub fn delete(self: Dict, key: ByteArray) -> Dict { Dict { inner: do_delete(self.inner, key) } } fn do_delete( - self: List<(ByteArray, value)>, + self: Map, key k: ByteArray, -) -> List<(ByteArray, value)> { +) -> Map { when self is { [] -> [] - [(k2, v2), ..rest] -> + [Pair(k2, v2), ..rest] -> if builtin.less_than_equals_bytearray(k, k2) { if k == k2 { rest @@ -74,7 +74,7 @@ fn do_delete( self } } else { - [(k2, v2), ..do_delete(rest, k)] + [Pair(k2, v2), ..do_delete(rest, k)] } } } @@ -139,9 +139,9 @@ test delete_6() { /// |> dict.insert(key: "b", value: 200) /// |> dict.insert(key: "c", value: 300) /// |> dict.filter(fn(k, _v) { k != "a" }) -/// |> dict.to_list() +/// |> dict.to_map() /// -/// result == [("b", 200), ("c", 300)] +/// result == [Pair("b", 200), Pair("c", 300)] /// ``` pub fn filter( self: Dict, @@ -151,15 +151,15 @@ pub fn filter( } fn do_filter( - self: List<(ByteArray, value)>, + self: Map, with: fn(ByteArray, value) -> Bool, -) -> List<(ByteArray, value)> { +) -> Map { when self is { [] -> [] - [(k, v), ..rest] -> + [Pair(k, v), ..rest] -> if with(k, v) { - [(k, v), ..do_filter(rest, with)] + [Pair(k, v), ..do_filter(rest, with)] } else { do_filter(rest, with) } @@ -200,10 +200,10 @@ pub fn find(self: Dict, value v: value) -> Option { do_find(self.inner, v) } -fn do_find(self: List<(ByteArray, value)>, value v: value) -> Option { +fn do_find(self: Map, value v: value) -> Option { when self is { [] -> None - [(k2, v2), ..rest] -> + [Pair(k2, v2), ..rest] -> if v == v2 { Some(k2) } else { @@ -264,13 +264,13 @@ pub fn foldr( } fn do_foldr( - self: List<(ByteArray, value)>, + self: Map, zero: result, with: fn(ByteArray, value, result) -> result, ) -> result { when self is { [] -> zero - [(k, v), ..rest] -> with(k, v, do_foldr(rest, zero, with)) + [Pair(k, v), ..rest] -> with(k, v, do_foldr(rest, zero, with)) } } @@ -304,13 +304,13 @@ pub fn foldl( } fn do_foldl( - self: List<(ByteArray, value)>, + self: Map, zero: result, with: fn(ByteArray, value, result) -> result, ) -> result { when self is { [] -> zero - [(k, v), ..rest] -> do_foldl(rest, with(k, v, zero), with) + [Pair(k, v), ..rest] -> do_foldl(rest, with(k, v, zero), with) } } @@ -326,159 +326,159 @@ test fold_2() { /// multiple times, the first occurrence prevails. /// /// ```aiken -/// let list = [("a", 100), ("c", 300), ("b", 200)] +/// let map = [Pair("a", 100), Pair("c", 300), Pair("b", 200)] /// /// let result = -/// dict.from_list(list) -/// |> dict.to_list() +/// dict.from_map(map) +/// |> dict.to_map() /// -/// result == [("a", 100), ("b", 200), ("c", 300)] +/// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn from_list(self: List<(ByteArray, value)>) -> Dict { - Dict { inner: do_from_list(self) } +pub fn from_map(self: Map) -> Dict { + Dict { inner: do_from_map(self) } } -fn do_from_list(xs: List<(ByteArray, value)>) -> List<(ByteArray, value)> { +fn do_from_map(xs: Map) -> Map { when xs is { [] -> [] - [(k, v), ..rest] -> do_insert(do_from_list(rest), k, v) + [Pair(k, v), ..rest] -> do_insert(do_from_map(rest), k, v) } } -test from_list_1() { - from_list([]) == new() +test from_map_1() { + from_map([]) == new() } -test from_list_2() { - from_list([(foo, 42), (bar, 14)]) == from_list([(bar, 14), (foo, 42)]) +test from_map_2() { + from_map([Pair(foo, 42), Pair(bar, 14)]) == from_map( + [Pair(bar, 14), Pair(foo, 42)], + ) } -test from_list_3() { - from_list([(foo, 42), (bar, 14)]) == fixture_1() +test from_map_3() { + from_map([Pair(foo, 42), Pair(bar, 14)]) == fixture_1() } -test from_list_4() { - from_list([(foo, 42), (bar, 14), (foo, 1337)]) == fixture_1() +test from_map_4() { + from_map([Pair(foo, 42), Pair(bar, 14), Pair(foo, 1337)]) == fixture_1() } -test bench_from_list() { +test bench_from_map() { let dict = - from_list( + from_map( [ - ("bbba", 8), - ("bbab", 12), - ("aabb", 13), - ("aaab", 9), - ("bbbb", 16), - ("aaaa", 1), - ("aaba", 5), - ("abab", 10), - ("baba", 7), - ("baab", 11), - ("abaa", 2), - ("baaa", 3), - ("bbaa", 4), - ("babb", 15), - ("abbb", 14), - ("abba", 6), + Pair("bbba", 8), + Pair("bbab", 12), + Pair("aabb", 13), + Pair("aaab", 9), + Pair("bbbb", 16), + Pair("aaaa", 1), + Pair("aaba", 5), + Pair("abab", 10), + Pair("baba", 7), + Pair("baab", 11), + Pair("abaa", 2), + Pair("baaa", 3), + Pair("bbaa", 4), + Pair("babb", 15), + Pair("abbb", 14), + Pair("abba", 6), ], ) size(dict) == 16 } -/// Like ['from_list'](from_list), but from an already sorted list by ascending +/// Like ['from_map'](from_map), but from an already sorted list by ascending /// keys. This function fails (i.e. halt the program execution) if the list isn't /// sorted. /// /// ```aiken -/// let list = [("a", 100), ("b", 200), ("c", 300)] +/// let map = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// /// let result = -/// dict.from_ascending_list(list) -/// |> dict.to_list() +/// dict.from_ascending_map(map) +/// |> dict.to_map() /// -/// result == [("a", 100), ("b", 200), ("c", 300)] +/// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` /// /// This is meant to be used to turn a list constructed off-chain into a `Dict` /// which has taken care of maintaining interval invariants. This function still /// performs a sanity check on all keys to avoid silly mistakes. It is, however, -/// considerably faster than ['from_list'](from_list) -pub fn from_ascending_list(xs: List<(ByteArray, value)>) -> Dict { - let Void = check_ascending_list(xs) +/// considerably faster than ['from_map'](from_map) +pub fn from_ascending_map(xs: Map) -> Dict { + let Void = check_ascending_map(xs) Dict { inner: xs } } -fn check_ascending_list(xs: List<(ByteArray, value)>) { +fn check_ascending_map(xs: Map) { when xs is { [] -> Void [_] -> Void - [(x0, _), (x1, _) as e, ..rest] -> + [Pair(x0, _), Pair(x1, _) as e, ..rest] -> if builtin.less_than_bytearray(x0, x1) { - check_ascending_list([e, ..rest]) + check_ascending_map([e, ..rest]) } else { fail @"keys in associative list aren't in ascending order" } } } -pub fn from_ascending_list_with( - xs: List<(key, value)>, - compare: fn(key, key) -> Ordering, +pub fn from_ascending_map_with( + xs: Map, value_predicate: fn(value) -> Bool, ) -> Dict { - let Void = check_ascending_list_with(xs, compare, value_predicate) + let Void = check_ascending_map_with(xs, value_predicate) Dict { inner: xs } } -fn check_ascending_list_with( - xs: List<(key, value)>, - compare: fn(key, key) -> Ordering, +fn check_ascending_map_with( + xs: Map, value_predicate: fn(value) -> Bool, ) { when xs is { [] -> Void - [(_, v)] -> + [Pair(_, v)] -> if value_predicate(v) { Void } else { fail @"value doesn't satisfy predicate" } - [(x0, v0), (x1, _) as e, ..rest] -> - when compare(x0, x1) is { - Less -> - if value_predicate(v0) { - check_ascending_list_with([e, ..rest], compare, value_predicate) - } else { - fail @"value doesn't satisfy predicate" - } - _ -> fail @"keys in associative list aren't in ascending order" + [Pair(x0, v0), Pair(x1, _) as e, ..rest] -> + if builtin.less_than_bytearray(x0, x1) { + if value_predicate(v0) { + check_ascending_map_with([e, ..rest], value_predicate) + } else { + fail @"value doesn't satisfy predicate" + } + } else { + fail @"keys in associative list aren't in ascending order" } } } -test bench_from_ascending_list() { +test bench_from_ascending_map() { let dict = - from_ascending_list( + from_ascending_map( [ - ("aaaa", 1), - ("aaab", 9), - ("aaba", 5), - ("aabb", 13), - ("abaa", 2), - ("abab", 10), - ("abba", 6), - ("abbb", 14), - ("baaa", 3), - ("baab", 11), - ("baba", 7), - ("babb", 15), - ("bbaa", 4), - ("bbab", 12), - ("bbba", 8), - ("bbbb", 16), + Pair("aaaa", 1), + Pair("aaab", 9), + Pair("aaba", 5), + Pair("aabb", 13), + Pair("abaa", 2), + Pair("abab", 10), + Pair("abba", 6), + Pair("abbb", 14), + Pair("baaa", 3), + Pair("baab", 11), + Pair("baba", 7), + Pair("babb", 15), + Pair("bbaa", 4), + Pair("bbab", 12), + Pair("bbba", 8), + Pair("bbbb", 16), ], ) @@ -499,10 +499,10 @@ pub fn get(self: Dict, key: ByteArray) -> Option { do_get(self.inner, key) } -fn do_get(self: List<(ByteArray, value)>, key k: ByteArray) -> Option { +fn do_get(self: Map, key k: ByteArray) -> Option { when self is { [] -> None - [(k2, v), ..rest] -> + [Pair(k2, v), ..rest] -> if builtin.less_than_equals_bytearray(k, k2) { if k == k2 { Some(v) @@ -583,10 +583,10 @@ pub fn has_key(self: Dict, key k: ByteArray) -> Bool { do_has_key(self.inner, k) } -fn do_has_key(self: List<(ByteArray, value)>, key k: ByteArray) -> Bool { +fn do_has_key(self: Map, key k: ByteArray) -> Bool { when self is { [] -> False - [(k2, _), ..rest] -> + [Pair(k2, _), ..rest] -> if builtin.less_than_equals_bytearray(k, k2) { k == k2 } else { @@ -632,9 +632,9 @@ test has_key_4() { /// |> dict.insert(key: "a", value: 1) /// |> dict.insert(key: "b", value: 2) /// |> dict.insert(key: "a", value: 3) -/// |> dict.to_list() +/// |> dict.to_map() /// -/// result == [("a", 3), ("b", 2)] +/// result == [Pair("a", 3), Pair("b", 2)] /// ``` pub fn insert( self: Dict, @@ -645,21 +645,21 @@ pub fn insert( } fn do_insert( - self: List<(ByteArray, value)>, + self: Map, key k: ByteArray, value v: value, -) -> List<(ByteArray, value)> { +) -> Map { when self is { [] -> - [(k, v)] - [(k2, v2), ..rest] -> + [Pair(k, v)] + [Pair(k2, v2), ..rest] -> if builtin.less_than_bytearray(k, k2) { - [(k, v), ..self] + [Pair(k, v), ..self] } else { if k == k2 { - [(k, v), ..rest] + [Pair(k, v), ..rest] } else { - [(k2, v2), ..do_insert(rest, k, v)] + [Pair(k2, v2), ..do_insert(rest, k, v)] } } } @@ -697,9 +697,9 @@ test insert_2() { /// |> dict.insert_with(key: "a", value: 1, with: sum) /// |> dict.insert_with(key: "b", value: 2, with: sum) /// |> dict.insert_with(key: "a", value: 3, with: sum) -/// |> dict.to_list() +/// |> dict.to_map() /// -/// result == [("a", 4), ("b", 2)] +/// result == [Pair("a", 4), Pair("b", 2)] /// ``` pub fn insert_with( self: Dict, @@ -720,9 +720,9 @@ test insert_with_1() { new() |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) - |> to_list() + |> to_map() - result == [("bar", 2), ("foo", 1)] + result == [Pair("bar", 2), Pair("foo", 1)] } test insert_with_2() { @@ -734,9 +734,9 @@ test insert_with_2() { |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) |> insert_with(key: "foo", value: 3, with: sum) - |> to_list() + |> to_map() - result == [("bar", 2), ("foo", 4)] + result == [Pair("bar", 2), Pair("foo", 4)] } test insert_with_3() { @@ -755,9 +755,9 @@ test insert_with_3() { |> insert_with(key: "bar", value: 2, with: with) |> insert_with(key: "foo", value: 3, with: with) |> insert_with(key: "bar", value: 4, with: with) - |> to_list() + |> to_map() - result == [("foo", 1)] + result == [Pair("foo", 1)] } /// Efficiently checks whether a dictionary is empty. @@ -791,11 +791,11 @@ pub fn keys(self: Dict) -> List { do_keys(self.inner) } -fn do_keys(self: List<(ByteArray, value)>) -> List { +fn do_keys(self: Map) -> List { when self is { [] -> [] - [(k, _), ..rest] -> + [Pair(k, _), ..rest] -> [k, ..do_keys(rest)] } } @@ -821,23 +821,23 @@ test keys_2() { /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) /// |> dict.map(fn(_k, v) { v * 2 }) -/// |> dict.to_list() +/// |> dict.to_map() /// -/// result == [("a", 200), ("b", 400), ("c", 600)] +/// result == [Pair("a", 200), Pair("b", 400), Pair("c", 600)] /// ``` pub fn map(self: Dict, with: fn(ByteArray, a) -> b) -> Dict { Dict { inner: do_map(self.inner, with) } } fn do_map( - self: List<(ByteArray, a)>, + self: Map, with: fn(ByteArray, a) -> b, -) -> List<(ByteArray, b)> { +) -> Map { when self is { [] -> [] - [(k, v), ..rest] -> - [(k, with(k, v)), ..do_map(rest, with)] + [Pair(k, v), ..rest] -> + [Pair(k, with(k, v)), ..do_map(rest, with)] } } @@ -863,20 +863,20 @@ test map_2() { /// |> dict.insert("a", 100) /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) -/// |> dict.to_list() +/// |> dict.to_map() /// -/// result == [("a", 100), ("b", 200), ("c", 300)] +/// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn to_list(self: Dict) -> List<(ByteArray, value)> { +pub fn to_map(self: Dict) -> Map { self.inner } -test to_list_1() { - to_list(new()) == [] +test to_map_1() { + to_map(new()) == [] } -test to_list_2() { - to_list(fixture_1()) == [(bar, 14), (foo, 42)] +test to_map_2() { + to_map(fixture_1()) == [Pair(bar, 14), Pair(foo, 42)] } /// Return the number of key-value pairs in the dictionary. @@ -895,7 +895,7 @@ pub fn size(self: Dict) -> Int { do_size(self.inner) } -fn do_size(self: List<(key, value)>) -> Int { +fn do_size(self: Map) -> Int { when self is { [] -> 0 [_, ..rest] -> 1 + do_size(rest) @@ -925,13 +925,13 @@ test size_3() { /// right dictionary, values from the left are preferred (i.e. left-biaised). /// /// ```aiken -/// let left_dict = dict.from_list([("a", 100), ("b", 200)]) -/// let right_dict = dict.from_list([("a", 150), ("c", 300)]) +/// let left_dict = dict.from_list([Pair("a", 100), Pair("b", 200)]) +/// let right_dict = dict.from_list([Pair("a", 150), Pair("c", 300)]) /// /// let result = -/// dict.union(left_dict, right_dict) |> dict.to_list() +/// dict.union(left_dict, right_dict) |> dict.to_map() /// -/// result == [("a", 100), ("b", 200), ("c", 300)] +/// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` pub fn union( left: Dict, @@ -941,12 +941,12 @@ pub fn union( } fn do_union( - left: List<(ByteArray, value)>, - right: List<(ByteArray, value)>, -) -> List<(ByteArray, value)> { + left: Map, + right: Map, +) -> Map { when left is { [] -> right - [(k, v), ..rest] -> do_union(rest, do_insert(right, k, v)) + [Pair(k, v), ..rest] -> do_union(rest, do_insert(right, k, v)) } } @@ -966,7 +966,9 @@ test union_3() { new() |> insert(bar, 42) |> insert(baz, 1337) - union(left, right) == from_list([(foo, 14), (baz, 1337), (bar, 42)]) + union(left, right) == from_map( + [Pair(foo, 14), Pair(baz, 1337), Pair(bar, 42)], + ) } test union_4() { @@ -977,7 +979,7 @@ test union_4() { new() |> insert(bar, 42) |> insert(foo, 1337) - union(left, right) == from_list([(foo, 14), (bar, 42)]) + union(left, right) == from_map([Pair(foo, 14), Pair(bar, 42)]) } /// Like [`union`](#union) but allows specifying the behavior to adopt when a key is present @@ -987,8 +989,8 @@ test union_4() { /// When passing `None`, the value is removed and not present in the union. /// /// ```aiken -/// let left_dict = dict.from_list([("a", 100), ("b", 200)]) -/// let right_dict = dict.from_list([("a", 150), ("c", 300)]) +/// let left_dict = dict.from_map([Pair("a", 100), Pair("b", 200)]) +/// let right_dict = dict.from_map([Pair("a", 150), Pair("c", 300)]) /// /// let result = /// dict.union_with( @@ -996,9 +998,9 @@ test union_4() { /// right_dict, /// fn(_k, v1, v2) { Some(v1 + v2) }, /// ) -/// |> dict.to_list() +/// |> dict.to_map() /// -/// result == [("a", 250), ("b", 200), ("c", 300)] +/// result == [Pair("a", 250), Pair("b", 200), Pair("c", 300)] /// ``` pub fn union_with( left: Dict, @@ -1009,38 +1011,38 @@ pub fn union_with( } fn do_union_with( - left: List<(ByteArray, value)>, - right: List<(ByteArray, value)>, + left: Map, + right: Map, with: fn(ByteArray, value, value) -> Option, -) -> List<(ByteArray, value)> { +) -> Map { when left is { [] -> right - [(k, v), ..rest] -> + [Pair(k, v), ..rest] -> do_union_with(rest, do_insert_with(right, k, v, with), with) } } fn do_insert_with( - self: List<(ByteArray, value)>, + self: Map, key k: ByteArray, value v: value, with: fn(ByteArray, value, value) -> Option, -) -> List<(ByteArray, value)> { +) -> Map { when self is { [] -> - [(k, v)] - [(k2, v2), ..rest] -> + [Pair(k, v)] + [Pair(k2, v2), ..rest] -> if builtin.less_than_bytearray(k, k2) { - [(k, v), ..self] + [Pair(k, v), ..self] } else { if k == k2 { when with(k, v, v2) is { Some(combined) -> - [(k, combined), ..rest] + [Pair(k, combined), ..rest] None -> rest } } else { - [(k2, v2), ..do_insert_with(rest, k, v, with)] + [Pair(k2, v2), ..do_insert_with(rest, k, v, with)] } } } @@ -1058,7 +1060,7 @@ test union_with_1() { let result = union_with(left, right, with: fn(_, l, r) { Some(l + r) }) - result == from_list([(foo, 1351), (bar, 42)]) + result == from_map([Pair(foo, 1351), Pair(bar, 42)]) } /// Extract all the values present in a given `Dict`. @@ -1077,11 +1079,11 @@ pub fn values(self: Dict) -> List { do_values(self.inner) } -fn do_values(self: List<(key, value)>) -> List { +fn do_values(self: Map) -> List { when self is { [] -> [] - [(_, v), ..rest] -> + [Pair(_, v), ..rest] -> [v, ..do_values(rest)] } } diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index fb020ed..f81d147 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -59,10 +59,10 @@ pub type Transaction { fee: Value, mint: MintedValue, certificates: List, - withdrawals: Dict, + withdrawals: Map, validity_range: ValidityRange, extra_signatories: List>, - redeemers: Dict, + redeemers: Map, datums: Dict, Data>, id: TransactionId, } @@ -89,10 +89,10 @@ pub fn placeholder() -> Transaction { fee: value.zero(), mint: value.zero() |> value.to_minted_value(), certificates: [], - withdrawals: dict.new(), + withdrawals: [], validity_range: interval.everything(), extra_signatories: [], - redeemers: dict.new(), + redeemers: [], datums: dict.new(), id: TransactionId { hash: #"0000000000000000000000000000000000000000000000000000000000000000", @@ -191,7 +191,7 @@ pub fn find_datum( InlineDatum(data) -> if blake2b_256(builtin.serialise_data(data)) == datum_hash{ - + Some(data) } else { None diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index d5a2063..2bcd720 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -1,4 +1,4 @@ -use aiken/dict.{Dict, from_ascending_list_with} +use aiken/dict.{Dict, from_ascending_map_with} use aiken/hash.{Blake2b_224, Hash} use aiken/list use aiken/option @@ -230,7 +230,7 @@ pub fn add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_list([(asset_name, quantity)]), + dict.from_ascending_map([Pair(asset_name, quantity)]), helper, ), ) @@ -436,14 +436,14 @@ test reduce_3() { /// /// This function is meant to turn arbitrary user-defined `Data` into safe `Value`, /// while checking for internal invariants. -pub fn from_asset_list(xs: List<(PolicyId, List<(AssetName, Int)>)>) -> Value { +pub fn from_asset_list(xs: Map>) -> Value { xs |> list.foldr( dict.new(), fn(inner, acc) { - expect (p, [_, ..] as x) = inner + expect Pair(p, [_, ..] as x) = inner x - |> from_ascending_list_with(bytearray.compare, fn(v) { v != 0 }) + |> from_ascending_map_with(fn(v) { v != 0 }) |> dict.insert_with( acc, p, @@ -451,7 +451,6 @@ pub fn from_asset_list(xs: List<(PolicyId, List<(AssetName, Int)>)>) -> Value { fn(_, _, _) { fail @"Duplicate policy in the asset list." }, - bytearray.compare, ) }, ) @@ -464,29 +463,32 @@ test from_asset_list_1() { } test from_asset_list_2() fail { - let v = from_asset_list([(#"33", [])]) + let v = from_asset_list([Pair(#"33", [])]) v == zero() } test from_asset_list_3() fail { - let v = from_asset_list([(#"33", [(#"", 0)])]) + let v = from_asset_list([Pair(#"33", [Pair(#"", 0)])]) v != zero() } test from_asset_list_4() { - let v = from_asset_list([(#"33", [(#"", 1)])]) + let v = from_asset_list([Pair(#"33", [Pair(#"", 1)])]) flatten(v) == [(#"33", #"", 1)] } test from_asset_list_5() { - let v = from_asset_list([(#"33", [(#"", 1), (#"33", 1)])]) + let v = from_asset_list([Pair(#"33", [Pair(#"", 1), Pair(#"33", 1)])]) flatten(v) == [(#"33", #"", 1), (#"33", #"33", 1)] } test from_asset_list_6() fail { let v = from_asset_list( - [(#"33", [(#"", 1), (#"33", 1)]), (#"33", [(#"", 1), (#"33", 1)])], + [ + Pair(#"33", [Pair(#"", 1), Pair(#"33", 1)]), + Pair(#"33", [Pair(#"", 1), Pair(#"33", 1)]), + ], ) v != zero() } @@ -494,7 +496,10 @@ test from_asset_list_6() fail { test from_asset_list_7() fail { let v = from_asset_list( - [(#"33", [(#"", 1), (#"33", 1)]), (#"34", [(#"", 1), (#"", 1)])], + [ + Pair(#"33", [Pair(#"", 1), Pair(#"33", 1)]), + Pair(#"34", [Pair(#"", 1), Pair(#"", 1)]), + ], ) v != zero() } @@ -503,9 +508,9 @@ test from_asset_list_8() { let v = from_asset_list( [ - (#"33", [(#"", 1), (#"33", 1)]), - (#"34", [(#"31", 1)]), - (#"35", [(#"", 1)]), + Pair(#"33", [Pair(#"", 1), Pair(#"33", 1)]), + Pair(#"34", [Pair(#"31", 1)]), + Pair(#"35", [Pair(#"", 1)]), ], ) flatten(v) == [ @@ -520,9 +525,9 @@ test from_asset_list_9() { let v = from_asset_list( [ - (#"35", [(#"", 1)]), - (#"33", [(#"", 1), (#"33", 1)]), - (#"34", [(#"31", 1)]), + Pair(#"35", [Pair(#"", 1)]), + Pair(#"33", [Pair(#"", 1), Pair(#"33", 1)]), + Pair(#"34", [Pair(#"31", 1)]), ], ) flatten(v) == [ @@ -623,7 +628,7 @@ pub fn to_minted_value(self: Value) -> MintedValue { test to_minted_value_1() { let minted_value = to_minted_value(zero()) - ( minted_value.inner |> dict.to_list |> list.length ) == 1 + ( minted_value.inner |> dict.to_map |> list.length ) == 1 } test to_minted_value_2() { @@ -660,7 +665,7 @@ fn unchecked_add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_list([(asset_name, quantity)]), + dict.from_ascending_map([Pair(asset_name, quantity)]), fn(_, left, _right) { Some( dict.insert_with( From 577a586b465dd502a9bd30107e1dfc61e7161ae3 Mon Sep 17 00:00:00 2001 From: microproofs Date: Mon, 29 Apr 2024 12:23:37 -0400 Subject: [PATCH 27/45] Define aiken/map interface for Map Unlike `Dict`, `Map` have no invariant and are simply mere wrapper around a list of pairs. Functions make no assumption about order of the keys and this is translated into the API which facilitate the access to underlying elements in various ways. Co-authored-by: KtorZ --- lib/aiken/dict.ak | 7 +- lib/aiken/map.ak | 580 +++++++++++++++++++++++++++++++++++++ lib/aiken/math/rational.ak | 2 +- 3 files changed, 585 insertions(+), 4 deletions(-) create mode 100644 lib/aiken/map.ak diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index 3bf918f..53d5441 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -23,7 +23,7 @@ pub opaque type Dict { inner: Map, } -/// Create a new map +/// Create a new empty Dict /// ```aiken /// dict.to_map(dict.new()) == [] /// ``` @@ -194,7 +194,7 @@ test filter_3() { /// |> dict.insert(key: "c", value: 42) /// |> dict.find(42) /// -/// result == Some("c") +/// result == Some("a") /// ``` pub fn find(self: Dict, value v: value) -> Option { do_find(self.inner, v) @@ -686,7 +686,8 @@ test insert_2() { } /// Insert a value in the dictionary at a given key. When the key already exist, the provided -/// merge function is called. +/// merge function is called. The value existing in the dictionary is passed as the second argument +/// to the merge function, and the new value is passed as the third argument. /// /// ```aiken /// let sum = diff --git a/lib/aiken/map.ak b/lib/aiken/map.ak new file mode 100644 index 0000000..f94099d --- /dev/null +++ b/lib/aiken/map.ak @@ -0,0 +1,580 @@ +//// A module for working with Map Data. +//// +//// These Maps are non-ordered lists of key-value pairs, +//// which preserve no invariant on the order of the keys or the duplication of keys. + +/// Remove a single key-value pair from the Map. If the key is not found, no changes are made. +/// Duplicate keys are not removed. Only the **first** key found is removed. +/// +/// ```aiken +/// map.remove_first([], "a") == [] +/// map.remove_first([Pair("a", 1)], "a") == [] +/// map.remove_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// map.remove_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)] +/// ``` +pub fn remove_first(self: Map, key k: key) -> Map { + when self is { + [] -> + [] + [Pair(k2, v2), ..rest] -> + if k == k2 { + rest + } else { + [Pair(k2, v2), ..remove_first(rest, k)] + } + } +} + +test remove_first_1() { + remove_first([], "a") == [] +} + +test remove_first_2() { + remove_first([Pair("a", 14)], "a") == [] +} + +test remove_first_3() { + let fixture = + [Pair("a", 14)] + remove_first(fixture, "b") == fixture +} + +test remove_first_4() { + let fixture = + [Pair("a", 1), Pair("b", 2), Pair("a", 3)] + remove_first(fixture, "a") == [Pair("b", 2), Pair("a", 3)] +} + +/// Remove a single key-value pair from the Map. If the key is not found, no changes are made. +/// Duplicate keys are not removed. Only the **last** key found is removed. +/// +/// ```aiken +/// map.remove_last([], "a") == [] +/// map.remove_last([Pair("a", 1)], "a") == [] +/// map.remove_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// map.remove_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)] +/// ``` +pub fn remove_last(self: Map, key k: key) -> Map { + when self is { + [] -> + [] + [Pair(k2, v2), ..rest] -> + if k == k2 { + let tail = remove_last(rest, k) + if tail == rest { + rest + } else { + [Pair(k2, v2), ..tail] + } + } else { + [Pair(k2, v2), ..remove_last(rest, k)] + } + } +} + +test remove_last_1() { + remove_last([], "a") == [] +} + +test remove_last_2() { + remove_last([Pair("a", 14)], "a") == [] +} + +test remove_last_3() { + let fixture = + [Pair("a", 14)] + remove_last(fixture, "b") == fixture +} + +test remove_last_4() { + let fixture = + [Pair("a", 1), Pair("b", 2), Pair("a", 3)] + remove_last(fixture, "a") == [Pair("a", 1), Pair("b", 2)] +} + +/// Remove all key-value pairs matching the key from the Map. If the key is not found, no changes are made. +/// +/// ```aiken +/// map.remove_all([], "a") == [] +/// map.remove_all([Pair("a", 1)], "a") == [] +/// map.remove_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// map.remove_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)] +/// ``` +pub fn remove_all(self: Map, key k: key) -> Map { + when self is { + [] -> + [] + [Pair(k2, v2), ..rest] -> + if k == k2 { + remove_all(rest, k) + } else { + [Pair(k2, v2), ..remove_all(rest, k)] + } + } +} + +test remove_all_1() { + remove_all([], "a") == [] +} + +test remove_all_2() { + remove_all([Pair("a", 14)], "a") == [] +} + +test remove_all_3() { + let fixture = + [Pair("a", 14)] + remove_all(fixture, "b") == fixture +} + +test remove_all_4() { + let fixture = + [Pair("a", 1), Pair("b", 2), Pair("a", 3)] + remove_all(fixture, "a") == [Pair("b", 2)] +} + +/// Finds the first key in the map associated with a given value, if any. +/// +/// ```aiken +/// map.find_first([], 1) == None +/// map.find_first([Pair("a", 1)], 1) == Some("a") +/// map.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a") +/// map.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a") +/// ``` +pub fn find_first(self: Map, v: value) -> Option { + when self is { + [] -> None + [Pair(k2, v2), ..rest] -> + if v == v2 { + Some(k2) + } else { + find_first(rest, v) + } + } +} + +test find_first_1() { + find_first([], "a") == None +} + +test find_first_2() { + find_first([Pair("a", 14)], 14) == Some("a") +} + +test find_first_3() { + find_first([Pair("a", 14)], 42) == None +} + +test find_first_4() { + find_first([Pair("a", 14), Pair("b", 42), Pair("c", 14)], 14) == Some("a") +} + +/// Finds the last key in the map associated with a given value, if any. +/// +/// ```aiken +/// map.find_last([], 1) == None +/// map.find_last([Pair("a", 1)], 1) == Some("a") +/// map.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a") +/// map.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c") +/// ``` +pub fn find_last(self: Map, v: value) -> Option { + when self is { + [] -> None + [Pair(k2, v2), ..rest] -> + if v == v2 { + when find_last(rest, v) is { + None -> Some(k2) + some -> some + } + } else { + find_last(rest, v) + } + } +} + +test find_last_1() { + find_last([], "a") == None +} + +test find_last_2() { + find_last([Pair("a", 14)], 14) == Some("a") +} + +test find_last_3() { + find_last([Pair("a", 14)], 42) == None +} + +test find_last_4() { + find_last([Pair("a", 14), Pair("b", 42), Pair("c", 14)], 14) == Some("c") +} + +/// Finds all keys in the map associated with a given value. +/// +/// ```aiken +/// map.find_all([], 1) == [] +/// map.find_all([Pair("a", 1)], 1) == ["a"] +/// map.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"] +/// map.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"] +/// ``` +pub fn find_all(self: Map, v: value) -> List { + when self is { + [] -> + [] + [Pair(k2, v2), ..rest] -> + if v == v2 { + [k2, ..find_all(rest, v)] + } else { + find_all(rest, v) + } + } +} + +test find_all_1() { + find_all([], "a") == [] +} + +test find_all_2() { + find_all([Pair("a", 14)], 14) == ["a"] +} + +test find_all_3() { + find_all([Pair("a", 14)], 42) == [] +} + +test find_all_4() { + find_all([Pair("a", 14), Pair("b", 42), Pair("c", 14)], 14) == ["a", "c"] +} + +/// Fold over the key-value pairs in a Map. The fold direction follows the +/// order of elements in the Map and is done from right-to-left. +/// +/// ```aiken +/// let fixture = [ +/// Pair(1, 100), +/// Pair(2, 200), +/// Pair(3, 300), +/// ] +/// +/// map.foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 +/// ``` +pub fn foldr( + self: Map, + zero: result, + with: fn(key, value, result) -> result, +) -> result { + when self is { + [] -> zero + [Pair(k, v), ..rest] -> with(k, v, foldr(rest, zero, with)) + } +} + +test foldr_1() { + foldr([], 14, fn(_, _, _) { 42 }) == 14 +} + +test foldr_2() { + foldr( + [Pair("a", 42), Pair("b", 14)], + zero: 0, + with: fn(_, v, total) { v + total }, + ) == 56 +} + +test foldr_3() { + let fixture = + [Pair(1, 100), Pair(2, 200), Pair(3, 300)] + + foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 +} + +/// Fold over the key-value pairs in a map. The fold direction follows keys +/// in ascending order and is done from left-to-right. +/// +/// ```aiken +/// let fixture = [ +/// Pair(1, 100), +/// Pair(2, 200), +/// Pair(3, 300), +/// ] +/// +/// map.foldl(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 +/// ``` +pub fn foldl( + self: Map, + zero: result, + with: fn(key, value, result) -> result, +) -> result { + when self is { + [] -> zero + [Pair(k, v), ..rest] -> foldl(rest, with(k, v, zero), with) + } +} + +test foldl_1() { + foldl([], 14, fn(_, _, _) { 42 }) == 14 +} + +test foldl_2() { + foldl( + [Pair("a", 42), Pair("b", 14)], + zero: 0, + with: fn(_, v, total) { v + total }, + ) == 56 +} + +/// Get the value in the map by its key. +/// If multiple values with the same key exist, only the first one is returned. +/// +/// ```aiken +/// map.get_first([], "a") == None +/// map.get_first([Pair("a", 1)], "a") == Some(1) +/// map.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +/// map.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) +/// ``` +pub fn get_first(self: Map, key k: key) -> Option { + when self is { + [] -> None + [Pair(k2, v), ..rest] -> + if k == k2 { + Some(v) + } else { + get_first(rest, k) + } + } +} + +test get_first_1() { + get_first([], "a") == None +} + +test get_first_2() { + get_first([Pair("a", 1)], "a") == Some(1) +} + +test get_first_3() { + get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +} + +test get_first_4() { + get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) +} + +test get_first_5() { + get_first([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "d") == None +} + +/// Get the value in the map by its key. +/// If multiple values with the same key exist, only the last one is returned. +/// +/// ```aiken +/// map.get_last([], "a") == None +/// map.get_last([Pair("a", 1)], "a") == Some(1) +/// map.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +/// map.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) +/// ``` +pub fn get_last(self: Map, key k: key) -> Option { + when self is { + [] -> None + [Pair(k2, v), ..rest] -> + if k == k2 { + when get_last(rest, k) is { + None -> Some(v) + some -> some + } + } else { + get_last(rest, k) + } + } +} + +test get_last_1() { + get_last([], "a") == None +} + +test get_last_2() { + get_last([Pair("a", 1)], "a") == Some(1) +} + +test get_last_3() { + get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +} + +test get_last_4() { + get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) +} + +test get_last_5() { + get_last([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "d") == None +} + +/// Get all values in the map associated with a given key. +/// +/// ```aiken +/// map.get_all([], "a") == [] +/// map.get_all([Pair("a", 1)], "a") == [1] +/// map.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] +/// map.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] +/// ``` +pub fn get_all(self: Map, key k: key) -> List { + when self is { + [] -> + [] + [Pair(k2, v), ..rest] -> + if k == k2 { + [v, ..get_all(rest, k)] + } else { + get_all(rest, k) + } + } +} + +test get_all_1() { + get_all([], "a") == [] +} + +test get_all_2() { + get_all([Pair("a", 1)], "a") == [1] +} + +test get_all_3() { + get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] +} + +test get_all_4() { + get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] +} + +test get_all_5() { + get_all([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "d") == [] +} + +/// Check if a key exists in the map. +/// +/// ```aiken +/// map.has_key([], "a") == False +/// map.has_key([Pair("a", 1)], "a") == True +/// map.has_key([Pair("a", 1), Pair("b", 2)], "a") == True +/// map.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True +/// ``` +pub fn has_key(self: Map, k: key) -> Bool { + when self is { + [] -> False + // || is lazy so this is fine + [Pair(k2, _), ..rest] -> k == k2 || has_key(rest, k) + } +} + +test has_key_1() { + !has_key([], "a") +} + +test has_key_2() { + has_key([Pair("a", 14)], "a") +} + +test has_key_3() { + !has_key([Pair("a", 14)], "b") +} + +test has_key_4() { + has_key([Pair("a", 14), Pair("b", 42)], "b") +} + +test has_key_5() { + has_key([Pair("a", 14), Pair("b", 42), Pair("a", 42)], "a") +} + +/// Extract all the keys present in a given `Map`. +/// +/// ```aiken +/// map.keys([]) == [] +/// map.keys([Pair("a", 1)]) == ["a"] +/// map.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"] +/// map.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"] +/// ``` +pub fn keys(self: Map) -> List { + when self is { + [] -> + [] + [Pair(k, _), ..rest] -> + [k, ..keys(rest)] + } +} + +test keys_1() { + keys([]) == [] +} + +test keys_2() { + keys([Pair("a", 0)]) == ["a"] +} + +test keys_3() { + keys([Pair("a", 0), Pair("b", 0)]) == ["a", "b"] +} + +/// Apply a function to all key-value pairs in a map, replacing the values. +/// +/// ```aiken +/// let fixture = [Pair("a", 100), Pair("b", 200)] +/// +/// map.map(fixture, fn(_k, v) { v * 2 }) == [Pair("a", 200), Pair("b", 400)] +/// ``` +pub fn map( + self: Map, + with: fn(key, value) -> result, +) -> Map { + when self is { + [] -> + [] + [Pair(k, v), ..rest] -> + [Pair(k, with(k, v)), ..map(rest, with)] + } +} + +test map_1() { + let fixture = + [Pair("a", 1), Pair("b", 2)] + + map(fixture, with: fn(k, _) { k }) == [Pair("a", "a"), Pair("b", "b")] +} + +test map_2() { + let fixture = + [Pair("a", 1), Pair("b", 2)] + + map(fixture, with: fn(_, v) { v + 1 }) == [Pair("a", 2), Pair("b", 3)] +} + +/// Extract all the values present in a given `Map`. +/// +/// ```aiken +/// map.values([]) == [] +/// map.values([Pair("a", 1)]) == [1] +/// map.values([Pair("a", 1), Pair("b", 2)]) == [1, 2] +/// map.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] +/// ``` +pub fn values(self: Map) -> List { + when self is { + [] -> + [] + [Pair(_, v), ..rest] -> + [v, ..values(rest)] + } +} + +test values_1() { + values([]) == [] +} + +test values_2() { + values([Pair("a", 1)]) == [1] +} + +test values_3() { + values([Pair("a", 1), Pair("b", 2)]) == [1, 2] +} + +test values_4() { + values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] +} diff --git a/lib/aiken/math/rational.ak b/lib/aiken/math/rational.ak index e62a65d..6bca643 100644 --- a/lib/aiken/math/rational.ak +++ b/lib/aiken/math/rational.ak @@ -334,7 +334,7 @@ test ceil_1() { } } -/// Returns the proper fraction of a given `Rational` `r`. That is, a pair of +/// Returns the proper fraction of a given `Rational` `r`. That is, a 2-tuple of /// an `Int` and `Rational` (n, f) such that: /// /// - `r = n + f`; From c4419941e9e8a725aa99582ea434b04eac199b95 Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 2 May 2024 15:37:56 -0400 Subject: [PATCH 28/45] Rename Map to AList --- lib/aiken/{map.ak => alist.ak} | 50 +++++++++++++------------- lib/aiken/cbor.ak | 2 +- lib/aiken/dict.ak | 64 +++++++++++++++++----------------- 3 files changed, 58 insertions(+), 58 deletions(-) rename lib/aiken/{map.ak => alist.ak} (88%) diff --git a/lib/aiken/map.ak b/lib/aiken/alist.ak similarity index 88% rename from lib/aiken/map.ak rename to lib/aiken/alist.ak index f94099d..93983b4 100644 --- a/lib/aiken/map.ak +++ b/lib/aiken/alist.ak @@ -1,9 +1,9 @@ -//// A module for working with Map Data. +//// A module for working with AList Data. //// -//// These Maps are non-ordered lists of key-value pairs, +//// These ALists are non-ordered lists of key-value pairs, //// which preserve no invariant on the order of the keys or the duplication of keys. -/// Remove a single key-value pair from the Map. If the key is not found, no changes are made. +/// Remove a single key-value pair from the AList. If the key is not found, no changes are made. /// Duplicate keys are not removed. Only the **first** key found is removed. /// /// ```aiken @@ -12,7 +12,7 @@ /// map.remove_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] /// map.remove_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)] /// ``` -pub fn remove_first(self: Map, key k: key) -> Map { +pub fn remove_first(self: AList, key k: key) -> AList { when self is { [] -> [] @@ -45,7 +45,7 @@ test remove_first_4() { remove_first(fixture, "a") == [Pair("b", 2), Pair("a", 3)] } -/// Remove a single key-value pair from the Map. If the key is not found, no changes are made. +/// Remove a single key-value pair from the AList. If the key is not found, no changes are made. /// Duplicate keys are not removed. Only the **last** key found is removed. /// /// ```aiken @@ -54,7 +54,7 @@ test remove_first_4() { /// map.remove_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] /// map.remove_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)] /// ``` -pub fn remove_last(self: Map, key k: key) -> Map { +pub fn remove_last(self: AList, key k: key) -> AList { when self is { [] -> [] @@ -92,7 +92,7 @@ test remove_last_4() { remove_last(fixture, "a") == [Pair("a", 1), Pair("b", 2)] } -/// Remove all key-value pairs matching the key from the Map. If the key is not found, no changes are made. +/// Remove all key-value pairs matching the key from the AList. If the key is not found, no changes are made. /// /// ```aiken /// map.remove_all([], "a") == [] @@ -100,7 +100,7 @@ test remove_last_4() { /// map.remove_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] /// map.remove_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)] /// ``` -pub fn remove_all(self: Map, key k: key) -> Map { +pub fn remove_all(self: AList, key k: key) -> AList { when self is { [] -> [] @@ -141,7 +141,7 @@ test remove_all_4() { /// map.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a") /// map.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a") /// ``` -pub fn find_first(self: Map, v: value) -> Option { +pub fn find_first(self: AList, v: value) -> Option { when self is { [] -> None [Pair(k2, v2), ..rest] -> @@ -177,7 +177,7 @@ test find_first_4() { /// map.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a") /// map.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c") /// ``` -pub fn find_last(self: Map, v: value) -> Option { +pub fn find_last(self: AList, v: value) -> Option { when self is { [] -> None [Pair(k2, v2), ..rest] -> @@ -216,7 +216,7 @@ test find_last_4() { /// map.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"] /// map.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"] /// ``` -pub fn find_all(self: Map, v: value) -> List { +pub fn find_all(self: AList, v: value) -> List { when self is { [] -> [] @@ -245,8 +245,8 @@ test find_all_4() { find_all([Pair("a", 14), Pair("b", 42), Pair("c", 14)], 14) == ["a", "c"] } -/// Fold over the key-value pairs in a Map. The fold direction follows the -/// order of elements in the Map and is done from right-to-left. +/// Fold over the key-value pairs in a AList. The fold direction follows the +/// order of elements in the AList and is done from right-to-left. /// /// ```aiken /// let fixture = [ @@ -258,7 +258,7 @@ test find_all_4() { /// map.foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldr( - self: Map, + self: AList, zero: result, with: fn(key, value, result) -> result, ) -> result { @@ -300,7 +300,7 @@ test foldr_3() { /// map.foldl(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldl( - self: Map, + self: AList, zero: result, with: fn(key, value, result) -> result, ) -> result { @@ -331,7 +331,7 @@ test foldl_2() { /// map.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) /// map.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) /// ``` -pub fn get_first(self: Map, key k: key) -> Option { +pub fn get_first(self: AList, key k: key) -> Option { when self is { [] -> None [Pair(k2, v), ..rest] -> @@ -372,7 +372,7 @@ test get_first_5() { /// map.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) /// map.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) /// ``` -pub fn get_last(self: Map, key k: key) -> Option { +pub fn get_last(self: AList, key k: key) -> Option { when self is { [] -> None [Pair(k2, v), ..rest] -> @@ -415,7 +415,7 @@ test get_last_5() { /// map.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] /// map.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] /// ``` -pub fn get_all(self: Map, key k: key) -> List { +pub fn get_all(self: AList, key k: key) -> List { when self is { [] -> [] @@ -456,7 +456,7 @@ test get_all_5() { /// map.has_key([Pair("a", 1), Pair("b", 2)], "a") == True /// map.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True /// ``` -pub fn has_key(self: Map, k: key) -> Bool { +pub fn has_key(self: AList, k: key) -> Bool { when self is { [] -> False // || is lazy so this is fine @@ -484,7 +484,7 @@ test has_key_5() { has_key([Pair("a", 14), Pair("b", 42), Pair("a", 42)], "a") } -/// Extract all the keys present in a given `Map`. +/// Extract all the keys present in a given `AList`. /// /// ```aiken /// map.keys([]) == [] @@ -492,7 +492,7 @@ test has_key_5() { /// map.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"] /// map.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"] /// ``` -pub fn keys(self: Map) -> List { +pub fn keys(self: AList) -> List { when self is { [] -> [] @@ -521,9 +521,9 @@ test keys_3() { /// map.map(fixture, fn(_k, v) { v * 2 }) == [Pair("a", 200), Pair("b", 400)] /// ``` pub fn map( - self: Map, + self: AList, with: fn(key, value) -> result, -) -> Map { +) -> AList { when self is { [] -> [] @@ -546,7 +546,7 @@ test map_2() { map(fixture, with: fn(_, v) { v + 1 }) == [Pair("a", 2), Pair("b", 3)] } -/// Extract all the values present in a given `Map`. +/// Extract all the values present in a given `AList`. /// /// ```aiken /// map.values([]) == [] @@ -554,7 +554,7 @@ test map_2() { /// map.values([Pair("a", 1), Pair("b", 2)]) == [1, 2] /// map.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] /// ``` -pub fn values(self: Map) -> List { +pub fn values(self: AList) -> List { when self is { [] -> [] diff --git a/lib/aiken/cbor.ak b/lib/aiken/cbor.ak index 1e5e142..e4a1094 100644 --- a/lib/aiken/cbor.ak +++ b/lib/aiken/cbor.ak @@ -310,7 +310,7 @@ test diagnostic_10() { } test diagnostic_10_alt() { - let xs: Map = + let xs: AList = [] diagnostic(xs) == @"{}" } diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index 53d5441..b1eff02 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -20,7 +20,7 @@ use aiken/builtin /// Dict> /// ``` pub opaque type Dict { - inner: Map, + inner: AList, } /// Create a new empty Dict @@ -60,9 +60,9 @@ pub fn delete(self: Dict, key: ByteArray) -> Dict { } fn do_delete( - self: Map, + self: AList, key k: ByteArray, -) -> Map { +) -> AList { when self is { [] -> [] @@ -151,9 +151,9 @@ pub fn filter( } fn do_filter( - self: Map, + self: AList, with: fn(ByteArray, value) -> Bool, -) -> Map { +) -> AList { when self is { [] -> [] @@ -200,7 +200,7 @@ pub fn find(self: Dict, value v: value) -> Option { do_find(self.inner, v) } -fn do_find(self: Map, value v: value) -> Option { +fn do_find(self: AList, value v: value) -> Option { when self is { [] -> None [Pair(k2, v2), ..rest] -> @@ -264,7 +264,7 @@ pub fn foldr( } fn do_foldr( - self: Map, + self: AList, zero: result, with: fn(ByteArray, value, result) -> result, ) -> result { @@ -304,7 +304,7 @@ pub fn foldl( } fn do_foldl( - self: Map, + self: AList, zero: result, with: fn(ByteArray, value, result) -> result, ) -> result { @@ -334,11 +334,11 @@ test fold_2() { /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn from_map(self: Map) -> Dict { +pub fn from_map(self: AList) -> Dict { Dict { inner: do_from_map(self) } } -fn do_from_map(xs: Map) -> Map { +fn do_from_map(xs: AList) -> AList { when xs is { [] -> [] @@ -408,12 +408,12 @@ test bench_from_map() { /// which has taken care of maintaining interval invariants. This function still /// performs a sanity check on all keys to avoid silly mistakes. It is, however, /// considerably faster than ['from_map'](from_map) -pub fn from_ascending_map(xs: Map) -> Dict { +pub fn from_ascending_map(xs: AList) -> Dict { let Void = check_ascending_map(xs) Dict { inner: xs } } -fn check_ascending_map(xs: Map) { +fn check_ascending_map(xs: AList) { when xs is { [] -> Void [_] -> Void @@ -427,7 +427,7 @@ fn check_ascending_map(xs: Map) { } pub fn from_ascending_map_with( - xs: Map, + xs: AList, value_predicate: fn(value) -> Bool, ) -> Dict { let Void = check_ascending_map_with(xs, value_predicate) @@ -435,7 +435,7 @@ pub fn from_ascending_map_with( } fn check_ascending_map_with( - xs: Map, + xs: AList, value_predicate: fn(value) -> Bool, ) { when xs is { @@ -499,7 +499,7 @@ pub fn get(self: Dict, key: ByteArray) -> Option { do_get(self.inner, key) } -fn do_get(self: Map, key k: ByteArray) -> Option { +fn do_get(self: AList, key k: ByteArray) -> Option { when self is { [] -> None [Pair(k2, v), ..rest] -> @@ -583,7 +583,7 @@ pub fn has_key(self: Dict, key k: ByteArray) -> Bool { do_has_key(self.inner, k) } -fn do_has_key(self: Map, key k: ByteArray) -> Bool { +fn do_has_key(self: AList, key k: ByteArray) -> Bool { when self is { [] -> False [Pair(k2, _), ..rest] -> @@ -645,10 +645,10 @@ pub fn insert( } fn do_insert( - self: Map, + self: AList, key k: ByteArray, value v: value, -) -> Map { +) -> AList { when self is { [] -> [Pair(k, v)] @@ -792,7 +792,7 @@ pub fn keys(self: Dict) -> List { do_keys(self.inner) } -fn do_keys(self: Map) -> List { +fn do_keys(self: AList) -> List { when self is { [] -> [] @@ -831,9 +831,9 @@ pub fn map(self: Dict, with: fn(ByteArray, a) -> b) -> Dict { } fn do_map( - self: Map, + self: AList, with: fn(ByteArray, a) -> b, -) -> Map { +) -> AList { when self is { [] -> [] @@ -868,7 +868,7 @@ test map_2() { /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn to_map(self: Dict) -> Map { +pub fn to_map(self: Dict) -> AList { self.inner } @@ -896,7 +896,7 @@ pub fn size(self: Dict) -> Int { do_size(self.inner) } -fn do_size(self: Map) -> Int { +fn do_size(self: AList) -> Int { when self is { [] -> 0 [_, ..rest] -> 1 + do_size(rest) @@ -942,9 +942,9 @@ pub fn union( } fn do_union( - left: Map, - right: Map, -) -> Map { + left: AList, + right: AList, +) -> AList { when left is { [] -> right [Pair(k, v), ..rest] -> do_union(rest, do_insert(right, k, v)) @@ -1012,10 +1012,10 @@ pub fn union_with( } fn do_union_with( - left: Map, - right: Map, + left: AList, + right: AList, with: fn(ByteArray, value, value) -> Option, -) -> Map { +) -> AList { when left is { [] -> right [Pair(k, v), ..rest] -> @@ -1024,11 +1024,11 @@ fn do_union_with( } fn do_insert_with( - self: Map, + self: AList, key k: ByteArray, value v: value, with: fn(ByteArray, value, value) -> Option, -) -> Map { +) -> AList { when self is { [] -> [Pair(k, v)] @@ -1080,7 +1080,7 @@ pub fn values(self: Dict) -> List { do_values(self.inner) } -fn do_values(self: Map) -> List { +fn do_values(self: AList) -> List { when self is { [] -> [] From ccb2e279caf05963805da8f076f90a4df9002d12 Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 2 May 2024 15:40:46 -0400 Subject: [PATCH 29/45] missed 2 more places --- lib/aiken/transaction.ak | 4 ++-- lib/aiken/transaction/value.ak | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index f81d147..d689dce 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -59,10 +59,10 @@ pub type Transaction { fee: Value, mint: MintedValue, certificates: List, - withdrawals: Map, + withdrawals: AList, validity_range: ValidityRange, extra_signatories: List>, - redeemers: Map, + redeemers: AList, datums: Dict, Data>, id: TransactionId, } diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 2bcd720..7f34c6a 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -436,7 +436,7 @@ test reduce_3() { /// /// This function is meant to turn arbitrary user-defined `Data` into safe `Value`, /// while checking for internal invariants. -pub fn from_asset_list(xs: Map>) -> Value { +pub fn from_asset_list(xs: AList>) -> Value { xs |> list.foldr( dict.new(), From d962dcaaec2dcb555b0889cd1b6b146718cdc834 Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 2 May 2024 17:13:01 -0400 Subject: [PATCH 30/45] rename function --- lib/aiken/dict.ak | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index b1eff02..9a36115 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -25,7 +25,7 @@ pub opaque type Dict { /// Create a new empty Dict /// ```aiken -/// dict.to_map(dict.new()) == [] +/// dict.to_alist(dict.new()) == [] /// ``` pub fn new() -> Dict { Dict { inner: [] } @@ -51,7 +51,7 @@ fn fixture_1() { /// |> dict.insert(key: "a", value: 100) /// |> dict.insert(key: "b", value: 200) /// |> dict.delete(key: "a") -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("b", 200)] /// ``` @@ -139,7 +139,7 @@ test delete_6() { /// |> dict.insert(key: "b", value: 200) /// |> dict.insert(key: "c", value: 300) /// |> dict.filter(fn(k, _v) { k != "a" }) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("b", 200), Pair("c", 300)] /// ``` @@ -330,7 +330,7 @@ test fold_2() { /// /// let result = /// dict.from_map(map) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` @@ -399,7 +399,7 @@ test bench_from_map() { /// /// let result = /// dict.from_ascending_map(map) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` @@ -632,7 +632,7 @@ test has_key_4() { /// |> dict.insert(key: "a", value: 1) /// |> dict.insert(key: "b", value: 2) /// |> dict.insert(key: "a", value: 3) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("a", 3), Pair("b", 2)] /// ``` @@ -698,7 +698,7 @@ test insert_2() { /// |> dict.insert_with(key: "a", value: 1, with: sum) /// |> dict.insert_with(key: "b", value: 2, with: sum) /// |> dict.insert_with(key: "a", value: 3, with: sum) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("a", 4), Pair("b", 2)] /// ``` @@ -721,7 +721,7 @@ test insert_with_1() { new() |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) - |> to_map() + |> to_alist() result == [Pair("bar", 2), Pair("foo", 1)] } @@ -735,7 +735,7 @@ test insert_with_2() { |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) |> insert_with(key: "foo", value: 3, with: sum) - |> to_map() + |> to_alist() result == [Pair("bar", 2), Pair("foo", 4)] } @@ -756,7 +756,7 @@ test insert_with_3() { |> insert_with(key: "bar", value: 2, with: with) |> insert_with(key: "foo", value: 3, with: with) |> insert_with(key: "bar", value: 4, with: with) - |> to_map() + |> to_alist() result == [Pair("foo", 1)] } @@ -822,7 +822,7 @@ test keys_2() { /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) /// |> dict.map(fn(_k, v) { v * 2 }) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("a", 200), Pair("b", 400), Pair("c", 600)] /// ``` @@ -864,20 +864,20 @@ test map_2() { /// |> dict.insert("a", 100) /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn to_map(self: Dict) -> AList { +pub fn to_alist(self: Dict) -> AList { self.inner } -test to_map_1() { - to_map(new()) == [] +test to_alist_1() { + to_alist(new()) == [] } -test to_map_2() { - to_map(fixture_1()) == [Pair(bar, 14), Pair(foo, 42)] +test to_alist_2() { + to_alist(fixture_1()) == [Pair(bar, 14), Pair(foo, 42)] } /// Return the number of key-value pairs in the dictionary. @@ -930,7 +930,7 @@ test size_3() { /// let right_dict = dict.from_list([Pair("a", 150), Pair("c", 300)]) /// /// let result = -/// dict.union(left_dict, right_dict) |> dict.to_map() +/// dict.union(left_dict, right_dict) |> dict.to_alist() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` @@ -999,7 +999,7 @@ test union_4() { /// right_dict, /// fn(_k, v1, v2) { Some(v1 + v2) }, /// ) -/// |> dict.to_map() +/// |> dict.to_alist() /// /// result == [Pair("a", 250), Pair("b", 200), Pair("c", 300)] /// ``` From 0ae9197ccdc253cfab9562eacc58403a871c0196 Mon Sep 17 00:00:00 2001 From: microproofs Date: Sat, 4 May 2024 13:39:30 -0400 Subject: [PATCH 31/45] finish renaming to alist --- lib/aiken/alist.ak | 120 ++++++++++++++++----------------- lib/aiken/bytearray.ak | 5 +- lib/aiken/dict.ak | 72 ++++++++++---------- lib/aiken/transaction/value.ak | 10 +-- 4 files changed, 104 insertions(+), 103 deletions(-) diff --git a/lib/aiken/alist.ak b/lib/aiken/alist.ak index 93983b4..3ff90d3 100644 --- a/lib/aiken/alist.ak +++ b/lib/aiken/alist.ak @@ -7,10 +7,10 @@ /// Duplicate keys are not removed. Only the **first** key found is removed. /// /// ```aiken -/// map.remove_first([], "a") == [] -/// map.remove_first([Pair("a", 1)], "a") == [] -/// map.remove_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] -/// map.remove_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)] +/// alist.remove_first([], "a") == [] +/// alist.remove_first([Pair("a", 1)], "a") == [] +/// alist.remove_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// alist.remove_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)] /// ``` pub fn remove_first(self: AList, key k: key) -> AList { when self is { @@ -49,10 +49,10 @@ test remove_first_4() { /// Duplicate keys are not removed. Only the **last** key found is removed. /// /// ```aiken -/// map.remove_last([], "a") == [] -/// map.remove_last([Pair("a", 1)], "a") == [] -/// map.remove_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] -/// map.remove_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)] +/// alist.remove_last([], "a") == [] +/// alist.remove_last([Pair("a", 1)], "a") == [] +/// alist.remove_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// alist.remove_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)] /// ``` pub fn remove_last(self: AList, key k: key) -> AList { when self is { @@ -95,10 +95,10 @@ test remove_last_4() { /// Remove all key-value pairs matching the key from the AList. If the key is not found, no changes are made. /// /// ```aiken -/// map.remove_all([], "a") == [] -/// map.remove_all([Pair("a", 1)], "a") == [] -/// map.remove_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] -/// map.remove_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)] +/// alist.remove_all([], "a") == [] +/// alist.remove_all([Pair("a", 1)], "a") == [] +/// alist.remove_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// alist.remove_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)] /// ``` pub fn remove_all(self: AList, key k: key) -> AList { when self is { @@ -133,13 +133,13 @@ test remove_all_4() { remove_all(fixture, "a") == [Pair("b", 2)] } -/// Finds the first key in the map associated with a given value, if any. +/// Finds the first key in the alist associated with a given value, if any. /// /// ```aiken -/// map.find_first([], 1) == None -/// map.find_first([Pair("a", 1)], 1) == Some("a") -/// map.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a") -/// map.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a") +/// alist.find_first([], 1) == None +/// alist.find_first([Pair("a", 1)], 1) == Some("a") +/// alist.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a") +/// alist.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a") /// ``` pub fn find_first(self: AList, v: value) -> Option { when self is { @@ -169,13 +169,13 @@ test find_first_4() { find_first([Pair("a", 14), Pair("b", 42), Pair("c", 14)], 14) == Some("a") } -/// Finds the last key in the map associated with a given value, if any. +/// Finds the last key in the alist associated with a given value, if any. /// /// ```aiken -/// map.find_last([], 1) == None -/// map.find_last([Pair("a", 1)], 1) == Some("a") -/// map.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a") -/// map.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c") +/// alist.find_last([], 1) == None +/// alist.find_last([Pair("a", 1)], 1) == Some("a") +/// alist.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a") +/// alist.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c") /// ``` pub fn find_last(self: AList, v: value) -> Option { when self is { @@ -208,13 +208,13 @@ test find_last_4() { find_last([Pair("a", 14), Pair("b", 42), Pair("c", 14)], 14) == Some("c") } -/// Finds all keys in the map associated with a given value. +/// Finds all keys in the alist associated with a given value. /// /// ```aiken -/// map.find_all([], 1) == [] -/// map.find_all([Pair("a", 1)], 1) == ["a"] -/// map.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"] -/// map.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"] +/// alist.find_all([], 1) == [] +/// alist.find_all([Pair("a", 1)], 1) == ["a"] +/// alist.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"] +/// alist.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"] /// ``` pub fn find_all(self: AList, v: value) -> List { when self is { @@ -255,7 +255,7 @@ test find_all_4() { /// Pair(3, 300), /// ] /// -/// map.foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 +/// alist.foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldr( self: AList, @@ -287,7 +287,7 @@ test foldr_3() { foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 } -/// Fold over the key-value pairs in a map. The fold direction follows keys +/// Fold over the key-value pairs in a alist. The fold direction follows keys /// in ascending order and is done from left-to-right. /// /// ```aiken @@ -297,7 +297,7 @@ test foldr_3() { /// Pair(3, 300), /// ] /// -/// map.foldl(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 +/// alist.foldl(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldl( self: AList, @@ -322,14 +322,14 @@ test foldl_2() { ) == 56 } -/// Get the value in the map by its key. +/// Get the value in the alist by its key. /// If multiple values with the same key exist, only the first one is returned. /// /// ```aiken -/// map.get_first([], "a") == None -/// map.get_first([Pair("a", 1)], "a") == Some(1) -/// map.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) -/// map.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) +/// alist.get_first([], "a") == None +/// alist.get_first([Pair("a", 1)], "a") == Some(1) +/// alist.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +/// alist.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) /// ``` pub fn get_first(self: AList, key k: key) -> Option { when self is { @@ -363,14 +363,14 @@ test get_first_5() { get_first([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "d") == None } -/// Get the value in the map by its key. +/// Get the value in the alist by its key. /// If multiple values with the same key exist, only the last one is returned. /// /// ```aiken -/// map.get_last([], "a") == None -/// map.get_last([Pair("a", 1)], "a") == Some(1) -/// map.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) -/// map.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) +/// alist.get_last([], "a") == None +/// alist.get_last([Pair("a", 1)], "a") == Some(1) +/// alist.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +/// alist.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) /// ``` pub fn get_last(self: AList, key k: key) -> Option { when self is { @@ -407,13 +407,13 @@ test get_last_5() { get_last([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "d") == None } -/// Get all values in the map associated with a given key. +/// Get all values in the alist associated with a given key. /// /// ```aiken -/// map.get_all([], "a") == [] -/// map.get_all([Pair("a", 1)], "a") == [1] -/// map.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] -/// map.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] +/// alist.get_all([], "a") == [] +/// alist.get_all([Pair("a", 1)], "a") == [1] +/// alist.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] +/// alist.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] /// ``` pub fn get_all(self: AList, key k: key) -> List { when self is { @@ -448,13 +448,13 @@ test get_all_5() { get_all([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "d") == [] } -/// Check if a key exists in the map. +/// Check if a key exists in the alist. /// /// ```aiken -/// map.has_key([], "a") == False -/// map.has_key([Pair("a", 1)], "a") == True -/// map.has_key([Pair("a", 1), Pair("b", 2)], "a") == True -/// map.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True +/// alist.has_key([], "a") == False +/// alist.has_key([Pair("a", 1)], "a") == True +/// alist.has_key([Pair("a", 1), Pair("b", 2)], "a") == True +/// alist.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True /// ``` pub fn has_key(self: AList, k: key) -> Bool { when self is { @@ -487,10 +487,10 @@ test has_key_5() { /// Extract all the keys present in a given `AList`. /// /// ```aiken -/// map.keys([]) == [] -/// map.keys([Pair("a", 1)]) == ["a"] -/// map.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"] -/// map.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"] +/// alist.keys([]) == [] +/// alist.keys([Pair("a", 1)]) == ["a"] +/// alist.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"] +/// alist.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"] /// ``` pub fn keys(self: AList) -> List { when self is { @@ -513,12 +513,12 @@ test keys_3() { keys([Pair("a", 0), Pair("b", 0)]) == ["a", "b"] } -/// Apply a function to all key-value pairs in a map, replacing the values. +/// Apply a function to all key-value pairs in a alist, replacing the values. /// /// ```aiken /// let fixture = [Pair("a", 100), Pair("b", 200)] /// -/// map.map(fixture, fn(_k, v) { v * 2 }) == [Pair("a", 200), Pair("b", 400)] +/// alist.map(fixture, fn(_k, v) { v * 2 }) == [Pair("a", 200), Pair("b", 400)] /// ``` pub fn map( self: AList, @@ -549,10 +549,10 @@ test map_2() { /// Extract all the values present in a given `AList`. /// /// ```aiken -/// map.values([]) == [] -/// map.values([Pair("a", 1)]) == [1] -/// map.values([Pair("a", 1), Pair("b", 2)]) == [1, 2] -/// map.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] +/// alist.values([]) == [] +/// alist.values([Pair("a", 1)]) == [1] +/// alist.values([Pair("a", 1), Pair("b", 2)]) == [1, 2] +/// alist.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] /// ``` pub fn values(self: AList) -> List { when self is { diff --git a/lib/aiken/bytearray.ak b/lib/aiken/bytearray.ak index c9eb3f3..840079e 100644 --- a/lib/aiken/bytearray.ak +++ b/lib/aiken/bytearray.ak @@ -278,8 +278,9 @@ test from_string_2() { } /// Add a byte element in front of a `ByteArray`. When the given byte is -/// greater than 255, it wraps-around. So 256 is mapped to 0, 257 to 1, and so -/// forth. +/// greater than 255, it wraps-around. **PlutusV2 behavior** So 256 is mapped to 0, 257 to 1, and so +/// forth. +/// In PlutusV3 this will error instead of wrapping around. /// /// ```aiken /// bytearray.push(#"", 0) == #"00" diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index 9a36115..80d7d9c 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -326,47 +326,47 @@ test fold_2() { /// multiple times, the first occurrence prevails. /// /// ```aiken -/// let map = [Pair("a", 100), Pair("c", 300), Pair("b", 200)] +/// let alist = [Pair("a", 100), Pair("c", 300), Pair("b", 200)] /// /// let result = -/// dict.from_map(map) +/// dict.from_alist(alist) /// |> dict.to_alist() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn from_map(self: AList) -> Dict { - Dict { inner: do_from_map(self) } +pub fn from_alist(self: AList) -> Dict { + Dict { inner: do_from_alist(self) } } -fn do_from_map(xs: AList) -> AList { +fn do_from_alist(xs: AList) -> AList { when xs is { [] -> [] - [Pair(k, v), ..rest] -> do_insert(do_from_map(rest), k, v) + [Pair(k, v), ..rest] -> do_insert(do_from_alist(rest), k, v) } } -test from_map_1() { - from_map([]) == new() +test from_alist_1() { + from_alist([]) == new() } -test from_map_2() { - from_map([Pair(foo, 42), Pair(bar, 14)]) == from_map( +test from_alist_2() { + from_alist([Pair(foo, 42), Pair(bar, 14)]) == from_alist( [Pair(bar, 14), Pair(foo, 42)], ) } -test from_map_3() { - from_map([Pair(foo, 42), Pair(bar, 14)]) == fixture_1() +test from_alist_3() { + from_alist([Pair(foo, 42), Pair(bar, 14)]) == fixture_1() } -test from_map_4() { - from_map([Pair(foo, 42), Pair(bar, 14), Pair(foo, 1337)]) == fixture_1() +test from_alist_4() { + from_alist([Pair(foo, 42), Pair(bar, 14), Pair(foo, 1337)]) == fixture_1() } -test bench_from_map() { +test bench_from_alist() { let dict = - from_map( + from_alist( [ Pair("bbba", 8), Pair("bbab", 12), @@ -390,15 +390,15 @@ test bench_from_map() { size(dict) == 16 } -/// Like ['from_map'](from_map), but from an already sorted list by ascending +/// Like ['from_alist'](from_alist), but from an already sorted list by ascending /// keys. This function fails (i.e. halt the program execution) if the list isn't /// sorted. /// /// ```aiken -/// let map = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] +/// let alist = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// /// let result = -/// dict.from_ascending_map(map) +/// dict.from_ascending_alist(alist) /// |> dict.to_alist() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] @@ -407,34 +407,34 @@ test bench_from_map() { /// This is meant to be used to turn a list constructed off-chain into a `Dict` /// which has taken care of maintaining interval invariants. This function still /// performs a sanity check on all keys to avoid silly mistakes. It is, however, -/// considerably faster than ['from_map'](from_map) -pub fn from_ascending_map(xs: AList) -> Dict { - let Void = check_ascending_map(xs) +/// considerably faster than ['from_alist'](from_alist) +pub fn from_ascending_alist(xs: AList) -> Dict { + let Void = check_ascending_alist(xs) Dict { inner: xs } } -fn check_ascending_map(xs: AList) { +fn check_ascending_alist(xs: AList) { when xs is { [] -> Void [_] -> Void [Pair(x0, _), Pair(x1, _) as e, ..rest] -> if builtin.less_than_bytearray(x0, x1) { - check_ascending_map([e, ..rest]) + check_ascending_alist([e, ..rest]) } else { fail @"keys in associative list aren't in ascending order" } } } -pub fn from_ascending_map_with( +pub fn from_ascending_alist_with( xs: AList, value_predicate: fn(value) -> Bool, ) -> Dict { - let Void = check_ascending_map_with(xs, value_predicate) + let Void = check_ascending_alist_with(xs, value_predicate) Dict { inner: xs } } -fn check_ascending_map_with( +fn check_ascending_alist_with( xs: AList, value_predicate: fn(value) -> Bool, ) { @@ -449,7 +449,7 @@ fn check_ascending_map_with( [Pair(x0, v0), Pair(x1, _) as e, ..rest] -> if builtin.less_than_bytearray(x0, x1) { if value_predicate(v0) { - check_ascending_map_with([e, ..rest], value_predicate) + check_ascending_alist_with([e, ..rest], value_predicate) } else { fail @"value doesn't satisfy predicate" } @@ -459,9 +459,9 @@ fn check_ascending_map_with( } } -test bench_from_ascending_map() { +test bench_from_ascending_alist() { let dict = - from_ascending_map( + from_ascending_alist( [ Pair("aaaa", 1), Pair("aaab", 9), @@ -813,7 +813,7 @@ test keys_2() { ) == [bar, foo] } -/// Apply a function to all key-value pairs in a map. +/// Apply a function to all key-value pairs in a Dict. /// /// ```aiken /// let result = @@ -967,7 +967,7 @@ test union_3() { new() |> insert(bar, 42) |> insert(baz, 1337) - union(left, right) == from_map( + union(left, right) == from_alist( [Pair(foo, 14), Pair(baz, 1337), Pair(bar, 42)], ) } @@ -980,7 +980,7 @@ test union_4() { new() |> insert(bar, 42) |> insert(foo, 1337) - union(left, right) == from_map([Pair(foo, 14), Pair(bar, 42)]) + union(left, right) == from_alist([Pair(foo, 14), Pair(bar, 42)]) } /// Like [`union`](#union) but allows specifying the behavior to adopt when a key is present @@ -990,8 +990,8 @@ test union_4() { /// When passing `None`, the value is removed and not present in the union. /// /// ```aiken -/// let left_dict = dict.from_map([Pair("a", 100), Pair("b", 200)]) -/// let right_dict = dict.from_map([Pair("a", 150), Pair("c", 300)]) +/// let left_dict = dict.from_alist([Pair("a", 100), Pair("b", 200)]) +/// let right_dict = dict.from_alist([Pair("a", 150), Pair("c", 300)]) /// /// let result = /// dict.union_with( @@ -1061,7 +1061,7 @@ test union_with_1() { let result = union_with(left, right, with: fn(_, l, r) { Some(l + r) }) - result == from_map([Pair(foo, 1351), Pair(bar, 42)]) + result == from_alist([Pair(foo, 1351), Pair(bar, 42)]) } /// Extract all the values present in a given `Dict`. diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 7f34c6a..d3274c7 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -1,4 +1,4 @@ -use aiken/dict.{Dict, from_ascending_map_with} +use aiken/dict.{Dict, from_ascending_alist_with} use aiken/hash.{Blake2b_224, Hash} use aiken/list use aiken/option @@ -230,7 +230,7 @@ pub fn add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_map([Pair(asset_name, quantity)]), + dict.from_ascending_alist([Pair(asset_name, quantity)]), helper, ), ) @@ -443,7 +443,7 @@ pub fn from_asset_list(xs: AList>) -> Value { fn(inner, acc) { expect Pair(p, [_, ..] as x) = inner x - |> from_ascending_map_with(fn(v) { v != 0 }) + |> from_ascending_alist_with(fn(v) { v != 0 }) |> dict.insert_with( acc, p, @@ -628,7 +628,7 @@ pub fn to_minted_value(self: Value) -> MintedValue { test to_minted_value_1() { let minted_value = to_minted_value(zero()) - ( minted_value.inner |> dict.to_map |> list.length ) == 1 + ( minted_value.inner |> dict.to_alist |> list.length ) == 1 } test to_minted_value_2() { @@ -665,7 +665,7 @@ fn unchecked_add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_map([Pair(asset_name, quantity)]), + dict.from_ascending_alist([Pair(asset_name, quantity)]), fn(_, left, _right) { Some( dict.insert_with( From 87be7c0f7ba780948e65ccc6fa1f57feddf56b19 Mon Sep 17 00:00:00 2001 From: microproofs Date: Sat, 4 May 2024 14:06:07 -0400 Subject: [PATCH 32/45] fmt fix --- lib/aiken/transaction.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index d689dce..33f4033 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -191,7 +191,7 @@ pub fn find_datum( InlineDatum(data) -> if blake2b_256(builtin.serialise_data(data)) == datum_hash{ - + Some(data) } else { None From d2f196683d6c34b634ed20b012dec95edf25d809 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 10 May 2024 19:03:20 +0200 Subject: [PATCH 33/45] Rework doc for alist, rename some functions and fill-in CHANGELOG --- CHANGELOG.md | 7 +- lib/aiken/{alist.ak => associative_list.ak} | 16 ++- lib/aiken/dict.ak | 133 +++++++++++--------- lib/aiken/transaction/value.ak | 10 +- 4 files changed, 96 insertions(+), 70 deletions(-) rename lib/aiken/{alist.ak => associative_list.ak} (95%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e6363..24b4cf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,15 @@ # Changelog -## UNRELEASED +## v1.9.0 - UNRELEASED ### Added -N/A +- A new module [`aiken/associative_list`](https://aiken-lang.github.io/stdlib/aiken/associative_list.html) to work with associative lists (a.k.a. `AList`). ### Changed -- Specialized all `Dict`'s key as `ByteArray`, and thus remove the need for passing an extra comparison function. +- **BREAKING-CHANGE**
+ Specialized all `Dict`'s key to `ByteArray`, and thus remove the need for passing an extra comparison function in many functions. `Dict` are however still specialized with a phantom type for keys. ### Removed diff --git a/lib/aiken/alist.ak b/lib/aiken/associative_list.ak similarity index 95% rename from lib/aiken/alist.ak rename to lib/aiken/associative_list.ak index 3ff90d3..925f479 100644 --- a/lib/aiken/alist.ak +++ b/lib/aiken/associative_list.ak @@ -1,7 +1,17 @@ -//// A module for working with AList Data. +//// A module for working with associative lists (a.k.a `AList`). //// -//// These ALists are non-ordered lists of key-value pairs, -//// which preserve no invariant on the order of the keys or the duplication of keys. +//// While any function that works on `List` also work on `AList`, this module provides some extra helpers +//// that are specifically tailored to working with associative lists. Fundamentally, an `AList` is +//// a type-alias to `List>`. +//// +//// ### Important +//// +//// Unlike dictionnaries (a.k.a. `Dict`), associative lists make no assumption +//// about the ordering of elements within the list. As a result, lookup +//// functions do traverse the entire list when invoked. They are also not _sets_, +//// and thus allow for duplicate keys. This is reflected in the functions used + +//to interact with them. /// Remove a single key-value pair from the AList. If the key is not found, no changes are made. /// Duplicate keys are not removed. Only the **first** key found is removed. diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index 80d7d9c..2c72927 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -1,8 +1,15 @@ //// A module for working with bytearray dictionaries. //// -//// These dictionaries are fundamentally ordered lists of key-value pairs, -//// which preserve some invariants. In particular, each key is only present -//// once in the dictionary. +//// ### Important +//// +//// Dictionaries are **ordered sets** of key-value pairs, which thus +//// preserve some invariants. Specifically, each key is only present once in +//// the dictionary and all keys are stored in ascending lexicographic order. +//// +//// These invariants allow for more optimized functions to operate on `Dict`, +//// but as a trade-offs, prevent `Dict` from being serializable. To recover a `Dict` +//// from an unknown `Data`, you must first recover an `AList` and use +//// `dict.from_ascending_list`. use aiken/builtin @@ -25,7 +32,7 @@ pub opaque type Dict { /// Create a new empty Dict /// ```aiken -/// dict.to_alist(dict.new()) == [] +/// dict.to_list(dict.new()) == [] /// ``` pub fn new() -> Dict { Dict { inner: [] } @@ -51,7 +58,7 @@ fn fixture_1() { /// |> dict.insert(key: "a", value: 100) /// |> dict.insert(key: "b", value: 200) /// |> dict.delete(key: "a") -/// |> dict.to_alist() +/// |> dict.to_list() /// /// result == [Pair("b", 200)] /// ``` @@ -139,7 +146,7 @@ test delete_6() { /// |> dict.insert(key: "b", value: 200) /// |> dict.insert(key: "c", value: 300) /// |> dict.filter(fn(k, _v) { k != "a" }) -/// |> dict.to_alist() +/// |> dict.to_list() /// /// result == [Pair("b", 200), Pair("c", 300)] /// ``` @@ -329,44 +336,44 @@ test fold_2() { /// let alist = [Pair("a", 100), Pair("c", 300), Pair("b", 200)] /// /// let result = -/// dict.from_alist(alist) -/// |> dict.to_alist() +/// dict.from_list(alist) +/// |> dict.to_list() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn from_alist(self: AList) -> Dict { - Dict { inner: do_from_alist(self) } +pub fn from_list(self: AList) -> Dict { + Dict { inner: do_from_list(self) } } -fn do_from_alist(xs: AList) -> AList { +fn do_from_list(xs: AList) -> AList { when xs is { [] -> [] - [Pair(k, v), ..rest] -> do_insert(do_from_alist(rest), k, v) + [Pair(k, v), ..rest] -> do_insert(do_from_list(rest), k, v) } } -test from_alist_1() { - from_alist([]) == new() +test from_list_1() { + from_list([]) == new() } -test from_alist_2() { - from_alist([Pair(foo, 42), Pair(bar, 14)]) == from_alist( +test from_list_2() { + from_list([Pair(foo, 42), Pair(bar, 14)]) == from_list( [Pair(bar, 14), Pair(foo, 42)], ) } -test from_alist_3() { - from_alist([Pair(foo, 42), Pair(bar, 14)]) == fixture_1() +test from_list_3() { + from_list([Pair(foo, 42), Pair(bar, 14)]) == fixture_1() } -test from_alist_4() { - from_alist([Pair(foo, 42), Pair(bar, 14), Pair(foo, 1337)]) == fixture_1() +test from_list_4() { + from_list([Pair(foo, 42), Pair(bar, 14), Pair(foo, 1337)]) == fixture_1() } -test bench_from_alist() { +test bench_from_list() { let dict = - from_alist( + from_list( [ Pair("bbba", 8), Pair("bbab", 12), @@ -390,7 +397,7 @@ test bench_from_alist() { size(dict) == 16 } -/// Like ['from_alist'](from_alist), but from an already sorted list by ascending +/// Like ['from_list'](from_list), but from an already sorted list by ascending /// keys. This function fails (i.e. halt the program execution) if the list isn't /// sorted. /// @@ -398,8 +405,8 @@ test bench_from_alist() { /// let alist = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// /// let result = -/// dict.from_ascending_alist(alist) -/// |> dict.to_alist() +/// dict.from_ascending_list(alist) +/// |> dict.to_list() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` @@ -407,49 +414,57 @@ test bench_from_alist() { /// This is meant to be used to turn a list constructed off-chain into a `Dict` /// which has taken care of maintaining interval invariants. This function still /// performs a sanity check on all keys to avoid silly mistakes. It is, however, -/// considerably faster than ['from_alist'](from_alist) -pub fn from_ascending_alist(xs: AList) -> Dict { - let Void = check_ascending_alist(xs) +/// considerably faster than ['from_list'](from_list) +pub fn from_ascending_list(xs: AList) -> Dict { + let Void = check_ascending_list(xs) Dict { inner: xs } } -fn check_ascending_alist(xs: AList) { +fn check_ascending_list(xs: AList) { when xs is { [] -> Void [_] -> Void [Pair(x0, _), Pair(x1, _) as e, ..rest] -> if builtin.less_than_bytearray(x0, x1) { - check_ascending_alist([e, ..rest]) + check_ascending_list([e, ..rest]) } else { fail @"keys in associative list aren't in ascending order" } } } -pub fn from_ascending_alist_with( +/// Like [`from_ascending_list`](#from_ascending_list) but fails if **any** +/// value doesn't satisfy the predicate. +/// +/// ```aiken +/// let alist = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] +/// +/// dict.from_ascending_list_with(alist, fn(x) { x <= 250 }) // fail +/// ``` +pub fn from_ascending_list_with( xs: AList, - value_predicate: fn(value) -> Bool, + predicate: fn(value) -> Bool, ) -> Dict { - let Void = check_ascending_alist_with(xs, value_predicate) + let Void = check_ascending_list_with(xs, predicate) Dict { inner: xs } } -fn check_ascending_alist_with( +fn check_ascending_list_with( xs: AList, - value_predicate: fn(value) -> Bool, + predicate: fn(value) -> Bool, ) { when xs is { [] -> Void [Pair(_, v)] -> - if value_predicate(v) { + if predicate(v) { Void } else { fail @"value doesn't satisfy predicate" } [Pair(x0, v0), Pair(x1, _) as e, ..rest] -> if builtin.less_than_bytearray(x0, x1) { - if value_predicate(v0) { - check_ascending_alist_with([e, ..rest], value_predicate) + if predicate(v0) { + check_ascending_list_with([e, ..rest], predicate) } else { fail @"value doesn't satisfy predicate" } @@ -459,9 +474,9 @@ fn check_ascending_alist_with( } } -test bench_from_ascending_alist() { +test bench_from_ascending_list() { let dict = - from_ascending_alist( + from_ascending_list( [ Pair("aaaa", 1), Pair("aaab", 9), @@ -632,7 +647,7 @@ test has_key_4() { /// |> dict.insert(key: "a", value: 1) /// |> dict.insert(key: "b", value: 2) /// |> dict.insert(key: "a", value: 3) -/// |> dict.to_alist() +/// |> dict.to_list() /// /// result == [Pair("a", 3), Pair("b", 2)] /// ``` @@ -698,7 +713,7 @@ test insert_2() { /// |> dict.insert_with(key: "a", value: 1, with: sum) /// |> dict.insert_with(key: "b", value: 2, with: sum) /// |> dict.insert_with(key: "a", value: 3, with: sum) -/// |> dict.to_alist() +/// |> dict.to_list() /// /// result == [Pair("a", 4), Pair("b", 2)] /// ``` @@ -721,7 +736,7 @@ test insert_with_1() { new() |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) - |> to_alist() + |> to_list() result == [Pair("bar", 2), Pair("foo", 1)] } @@ -735,7 +750,7 @@ test insert_with_2() { |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) |> insert_with(key: "foo", value: 3, with: sum) - |> to_alist() + |> to_list() result == [Pair("bar", 2), Pair("foo", 4)] } @@ -756,7 +771,7 @@ test insert_with_3() { |> insert_with(key: "bar", value: 2, with: with) |> insert_with(key: "foo", value: 3, with: with) |> insert_with(key: "bar", value: 4, with: with) - |> to_alist() + |> to_list() result == [Pair("foo", 1)] } @@ -822,7 +837,7 @@ test keys_2() { /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) /// |> dict.map(fn(_k, v) { v * 2 }) -/// |> dict.to_alist() +/// |> dict.to_list() /// /// result == [Pair("a", 200), Pair("b", 400), Pair("c", 600)] /// ``` @@ -864,20 +879,20 @@ test map_2() { /// |> dict.insert("a", 100) /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) -/// |> dict.to_alist() +/// |> dict.to_list() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn to_alist(self: Dict) -> AList { +pub fn to_list(self: Dict) -> AList { self.inner } -test to_alist_1() { - to_alist(new()) == [] +test to_list_1() { + to_list(new()) == [] } -test to_alist_2() { - to_alist(fixture_1()) == [Pair(bar, 14), Pair(foo, 42)] +test to_list_2() { + to_list(fixture_1()) == [Pair(bar, 14), Pair(foo, 42)] } /// Return the number of key-value pairs in the dictionary. @@ -930,7 +945,7 @@ test size_3() { /// let right_dict = dict.from_list([Pair("a", 150), Pair("c", 300)]) /// /// let result = -/// dict.union(left_dict, right_dict) |> dict.to_alist() +/// dict.union(left_dict, right_dict) |> dict.to_list() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` @@ -967,7 +982,7 @@ test union_3() { new() |> insert(bar, 42) |> insert(baz, 1337) - union(left, right) == from_alist( + union(left, right) == from_list( [Pair(foo, 14), Pair(baz, 1337), Pair(bar, 42)], ) } @@ -980,7 +995,7 @@ test union_4() { new() |> insert(bar, 42) |> insert(foo, 1337) - union(left, right) == from_alist([Pair(foo, 14), Pair(bar, 42)]) + union(left, right) == from_list([Pair(foo, 14), Pair(bar, 42)]) } /// Like [`union`](#union) but allows specifying the behavior to adopt when a key is present @@ -990,8 +1005,8 @@ test union_4() { /// When passing `None`, the value is removed and not present in the union. /// /// ```aiken -/// let left_dict = dict.from_alist([Pair("a", 100), Pair("b", 200)]) -/// let right_dict = dict.from_alist([Pair("a", 150), Pair("c", 300)]) +/// let left_dict = dict.from_list([Pair("a", 100), Pair("b", 200)]) +/// let right_dict = dict.from_list([Pair("a", 150), Pair("c", 300)]) /// /// let result = /// dict.union_with( @@ -999,7 +1014,7 @@ test union_4() { /// right_dict, /// fn(_k, v1, v2) { Some(v1 + v2) }, /// ) -/// |> dict.to_alist() +/// |> dict.to_list() /// /// result == [Pair("a", 250), Pair("b", 200), Pair("c", 300)] /// ``` @@ -1061,7 +1076,7 @@ test union_with_1() { let result = union_with(left, right, with: fn(_, l, r) { Some(l + r) }) - result == from_alist([Pair(foo, 1351), Pair(bar, 42)]) + result == from_list([Pair(foo, 1351), Pair(bar, 42)]) } /// Extract all the values present in a given `Dict`. diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index d3274c7..67e7930 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -1,4 +1,4 @@ -use aiken/dict.{Dict, from_ascending_alist_with} +use aiken/dict.{Dict, from_ascending_list_with} use aiken/hash.{Blake2b_224, Hash} use aiken/list use aiken/option @@ -230,7 +230,7 @@ pub fn add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_alist([Pair(asset_name, quantity)]), + dict.from_ascending_list([Pair(asset_name, quantity)]), helper, ), ) @@ -443,7 +443,7 @@ pub fn from_asset_list(xs: AList>) -> Value { fn(inner, acc) { expect Pair(p, [_, ..] as x) = inner x - |> from_ascending_alist_with(fn(v) { v != 0 }) + |> from_ascending_list_with(fn(v) { v != 0 }) |> dict.insert_with( acc, p, @@ -628,7 +628,7 @@ pub fn to_minted_value(self: Value) -> MintedValue { test to_minted_value_1() { let minted_value = to_minted_value(zero()) - ( minted_value.inner |> dict.to_alist |> list.length ) == 1 + ( minted_value.inner |> dict.to_list |> list.length ) == 1 } test to_minted_value_2() { @@ -665,7 +665,7 @@ fn unchecked_add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_alist([Pair(asset_name, quantity)]), + dict.from_ascending_list([Pair(asset_name, quantity)]), fn(_, left, _right) { Some( dict.insert_with( From fba13a5c7ac3873c8ca3d4c920b925983b56a30d Mon Sep 17 00:00:00 2001 From: dmitrystas Date: Wed, 22 May 2024 10:09:06 +0200 Subject: [PATCH 34/45] Update value.ak Add `minted_to_dict` method, just for consistency with other opaque types like Value, Dict, etc, that have methods to return inner value --- lib/aiken/transaction/value.ak | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index 67e7930..a2e65c0 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -555,6 +555,11 @@ pub opaque type MintedValue { inner: Dict>, } +/// Convert minted value into a dictionary of dictionaries. +pub fn minted_to_dict(self: MintedValue) -> Dict> { + self.inner +} + /// Convert a [`MintedValue`](#MintedValue) into a [`Value`](#Value). pub fn from_minted_value(self: MintedValue) -> Value { self.inner |> dict.delete(ada_policy_id) |> Value From 5a279d8b0570e25e0ee827ed0e22913da5c72f59 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Wed, 22 May 2024 10:42:58 +0200 Subject: [PATCH 35/45] Closes #82. --- lib/aiken/list.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/list.ak b/lib/aiken/list.ak index 6299e36..b8bb4b8 100644 --- a/lib/aiken/list.ak +++ b/lib/aiken/list.ak @@ -68,7 +68,7 @@ test any_3() { /// list.count([1, 2, 3], fn(a) { n > 5 }) == 0 /// ``` pub fn count(self: List, predicate: fn(a) -> Bool) -> Int { - foldl( + foldr( self, 0, fn(item, total) { From b281d4c6c3d57268d89ca29d9a4be27e7bbfd167 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 23 May 2024 16:50:18 +0200 Subject: [PATCH 36/45] Rename AList -> Pairs --- CHANGELOG.md | 8 +- lib/aiken/cbor.ak | 2 +- lib/aiken/dict.ak | 156 ++++++++++---------- lib/aiken/{associative_list.ak => pairs.ak} | 55 ++++--- lib/aiken/transaction.ak | 6 +- lib/aiken/transaction/value.ak | 12 +- 6 files changed, 122 insertions(+), 117 deletions(-) rename lib/aiken/{associative_list.ak => pairs.ak} (89%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b4cf5..fb8090a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,19 @@ ### Added -- A new module [`aiken/associative_list`](https://aiken-lang.github.io/stdlib/aiken/associative_list.html) to work with associative lists (a.k.a. `AList`). +- A new module [`aiken/pairs`](https://aiken-lang.github.io/stdlib/aiken/pairs.html) to work with associative lists (a.k.a. `Pairs`). ### Changed - **BREAKING-CHANGE**
Specialized all `Dict`'s key to `ByteArray`, and thus remove the need for passing an extra comparison function in many functions. `Dict` are however still specialized with a phantom type for keys. +- **BREAKING-CHANGE**
+ Few functions from `Dict` have been renamed for consistency: + - `from_list` -> `from_pairs` + - `from_ascending_list` -> `from_ascending_pairs` + - `to_list` -> `to_pairs` + ### Removed N/A diff --git a/lib/aiken/cbor.ak b/lib/aiken/cbor.ak index e4a1094..5a5ec2e 100644 --- a/lib/aiken/cbor.ak +++ b/lib/aiken/cbor.ak @@ -310,7 +310,7 @@ test diagnostic_10() { } test diagnostic_10_alt() { - let xs: AList = + let xs: Pairs = [] diagnostic(xs) == @"{}" } diff --git a/lib/aiken/dict.ak b/lib/aiken/dict.ak index 2c72927..d280443 100644 --- a/lib/aiken/dict.ak +++ b/lib/aiken/dict.ak @@ -8,7 +8,7 @@ //// //// These invariants allow for more optimized functions to operate on `Dict`, //// but as a trade-offs, prevent `Dict` from being serializable. To recover a `Dict` -//// from an unknown `Data`, you must first recover an `AList` and use +//// from an unknown `Data`, you must first recover an `Pairs` and use //// `dict.from_ascending_list`. use aiken/builtin @@ -27,12 +27,12 @@ use aiken/builtin /// Dict> /// ``` pub opaque type Dict { - inner: AList, + inner: Pairs, } /// Create a new empty Dict /// ```aiken -/// dict.to_list(dict.new()) == [] +/// dict.to_pairs(dict.new()) == [] /// ``` pub fn new() -> Dict { Dict { inner: [] } @@ -58,7 +58,7 @@ fn fixture_1() { /// |> dict.insert(key: "a", value: 100) /// |> dict.insert(key: "b", value: 200) /// |> dict.delete(key: "a") -/// |> dict.to_list() +/// |> dict.to_pairs() /// /// result == [Pair("b", 200)] /// ``` @@ -67,9 +67,9 @@ pub fn delete(self: Dict, key: ByteArray) -> Dict { } fn do_delete( - self: AList, + self: Pairs, key k: ByteArray, -) -> AList { +) -> Pairs { when self is { [] -> [] @@ -146,7 +146,7 @@ test delete_6() { /// |> dict.insert(key: "b", value: 200) /// |> dict.insert(key: "c", value: 300) /// |> dict.filter(fn(k, _v) { k != "a" }) -/// |> dict.to_list() +/// |> dict.to_pairs() /// /// result == [Pair("b", 200), Pair("c", 300)] /// ``` @@ -158,9 +158,9 @@ pub fn filter( } fn do_filter( - self: AList, + self: Pairs, with: fn(ByteArray, value) -> Bool, -) -> AList { +) -> Pairs { when self is { [] -> [] @@ -207,7 +207,7 @@ pub fn find(self: Dict, value v: value) -> Option { do_find(self.inner, v) } -fn do_find(self: AList, value v: value) -> Option { +fn do_find(self: Pairs, value v: value) -> Option { when self is { [] -> None [Pair(k2, v2), ..rest] -> @@ -271,7 +271,7 @@ pub fn foldr( } fn do_foldr( - self: AList, + self: Pairs, zero: result, with: fn(ByteArray, value, result) -> result, ) -> result { @@ -311,7 +311,7 @@ pub fn foldl( } fn do_foldl( - self: AList, + self: Pairs, zero: result, with: fn(ByteArray, value, result) -> result, ) -> result { @@ -333,47 +333,47 @@ test fold_2() { /// multiple times, the first occurrence prevails. /// /// ```aiken -/// let alist = [Pair("a", 100), Pair("c", 300), Pair("b", 200)] +/// let pairs = [Pair("a", 100), Pair("c", 300), Pair("b", 200)] /// /// let result = -/// dict.from_list(alist) -/// |> dict.to_list() +/// dict.from_pairs(pairs) +/// |> dict.to_pairs() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn from_list(self: AList) -> Dict { - Dict { inner: do_from_list(self) } +pub fn from_pairs(self: Pairs) -> Dict { + Dict { inner: do_from_pairs(self) } } -fn do_from_list(xs: AList) -> AList { +fn do_from_pairs(xs: Pairs) -> Pairs { when xs is { [] -> [] - [Pair(k, v), ..rest] -> do_insert(do_from_list(rest), k, v) + [Pair(k, v), ..rest] -> do_insert(do_from_pairs(rest), k, v) } } test from_list_1() { - from_list([]) == new() + from_pairs([]) == new() } test from_list_2() { - from_list([Pair(foo, 42), Pair(bar, 14)]) == from_list( + from_pairs([Pair(foo, 42), Pair(bar, 14)]) == from_pairs( [Pair(bar, 14), Pair(foo, 42)], ) } test from_list_3() { - from_list([Pair(foo, 42), Pair(bar, 14)]) == fixture_1() + from_pairs([Pair(foo, 42), Pair(bar, 14)]) == fixture_1() } test from_list_4() { - from_list([Pair(foo, 42), Pair(bar, 14), Pair(foo, 1337)]) == fixture_1() + from_pairs([Pair(foo, 42), Pair(bar, 14), Pair(foo, 1337)]) == fixture_1() } -test bench_from_list() { +test bench_from_pairs() { let dict = - from_list( + from_pairs( [ Pair("bbba", 8), Pair("bbab", 12), @@ -402,11 +402,11 @@ test bench_from_list() { /// sorted. /// /// ```aiken -/// let alist = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] +/// let pairs = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// /// let result = -/// dict.from_ascending_list(alist) -/// |> dict.to_list() +/// dict.from_ascending_pairs(pairs) +/// |> dict.to_pairs() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` @@ -415,12 +415,12 @@ test bench_from_list() { /// which has taken care of maintaining interval invariants. This function still /// performs a sanity check on all keys to avoid silly mistakes. It is, however, /// considerably faster than ['from_list'](from_list) -pub fn from_ascending_list(xs: AList) -> Dict { +pub fn from_ascending_pairs(xs: Pairs) -> Dict { let Void = check_ascending_list(xs) Dict { inner: xs } } -fn check_ascending_list(xs: AList) { +fn check_ascending_list(xs: Pairs) { when xs is { [] -> Void [_] -> Void @@ -433,24 +433,24 @@ fn check_ascending_list(xs: AList) { } } -/// Like [`from_ascending_list`](#from_ascending_list) but fails if **any** +/// Like [`from_ascending_pairs`](#from_ascending_list) but fails if **any** /// value doesn't satisfy the predicate. /// /// ```aiken -/// let alist = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] +/// let pairs = [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// -/// dict.from_ascending_list_with(alist, fn(x) { x <= 250 }) // fail +/// dict.from_ascending_pairs_with(pairs, fn(x) { x <= 250 }) // fail /// ``` -pub fn from_ascending_list_with( - xs: AList, +pub fn from_ascending_pairs_with( + xs: Pairs, predicate: fn(value) -> Bool, ) -> Dict { - let Void = check_ascending_list_with(xs, predicate) + let Void = check_ascending_pairs_with(xs, predicate) Dict { inner: xs } } -fn check_ascending_list_with( - xs: AList, +fn check_ascending_pairs_with( + xs: Pairs, predicate: fn(value) -> Bool, ) { when xs is { @@ -464,19 +464,19 @@ fn check_ascending_list_with( [Pair(x0, v0), Pair(x1, _) as e, ..rest] -> if builtin.less_than_bytearray(x0, x1) { if predicate(v0) { - check_ascending_list_with([e, ..rest], predicate) + check_ascending_pairs_with([e, ..rest], predicate) } else { fail @"value doesn't satisfy predicate" } } else { - fail @"keys in associative list aren't in ascending order" + fail @"keys in pairs aren't in ascending order" } } } -test bench_from_ascending_list() { +test bench_from_ascending_pairs() { let dict = - from_ascending_list( + from_ascending_pairs( [ Pair("aaaa", 1), Pair("aaab", 9), @@ -514,7 +514,7 @@ pub fn get(self: Dict, key: ByteArray) -> Option { do_get(self.inner, key) } -fn do_get(self: AList, key k: ByteArray) -> Option { +fn do_get(self: Pairs, key k: ByteArray) -> Option { when self is { [] -> None [Pair(k2, v), ..rest] -> @@ -598,7 +598,7 @@ pub fn has_key(self: Dict, key k: ByteArray) -> Bool { do_has_key(self.inner, k) } -fn do_has_key(self: AList, key k: ByteArray) -> Bool { +fn do_has_key(self: Pairs, key k: ByteArray) -> Bool { when self is { [] -> False [Pair(k2, _), ..rest] -> @@ -647,7 +647,7 @@ test has_key_4() { /// |> dict.insert(key: "a", value: 1) /// |> dict.insert(key: "b", value: 2) /// |> dict.insert(key: "a", value: 3) -/// |> dict.to_list() +/// |> dict.to_pairs() /// /// result == [Pair("a", 3), Pair("b", 2)] /// ``` @@ -660,10 +660,10 @@ pub fn insert( } fn do_insert( - self: AList, + self: Pairs, key k: ByteArray, value v: value, -) -> AList { +) -> Pairs { when self is { [] -> [Pair(k, v)] @@ -713,7 +713,7 @@ test insert_2() { /// |> dict.insert_with(key: "a", value: 1, with: sum) /// |> dict.insert_with(key: "b", value: 2, with: sum) /// |> dict.insert_with(key: "a", value: 3, with: sum) -/// |> dict.to_list() +/// |> dict.to_pairs() /// /// result == [Pair("a", 4), Pair("b", 2)] /// ``` @@ -736,7 +736,7 @@ test insert_with_1() { new() |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) - |> to_list() + |> to_pairs() result == [Pair("bar", 2), Pair("foo", 1)] } @@ -750,7 +750,7 @@ test insert_with_2() { |> insert_with(key: "foo", value: 1, with: sum) |> insert_with(key: "bar", value: 2, with: sum) |> insert_with(key: "foo", value: 3, with: sum) - |> to_list() + |> to_pairs() result == [Pair("bar", 2), Pair("foo", 4)] } @@ -771,7 +771,7 @@ test insert_with_3() { |> insert_with(key: "bar", value: 2, with: with) |> insert_with(key: "foo", value: 3, with: with) |> insert_with(key: "bar", value: 4, with: with) - |> to_list() + |> to_pairs() result == [Pair("foo", 1)] } @@ -807,7 +807,7 @@ pub fn keys(self: Dict) -> List { do_keys(self.inner) } -fn do_keys(self: AList) -> List { +fn do_keys(self: Pairs) -> List { when self is { [] -> [] @@ -837,7 +837,7 @@ test keys_2() { /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) /// |> dict.map(fn(_k, v) { v * 2 }) -/// |> dict.to_list() +/// |> dict.to_pairs() /// /// result == [Pair("a", 200), Pair("b", 400), Pair("c", 600)] /// ``` @@ -846,9 +846,9 @@ pub fn map(self: Dict, with: fn(ByteArray, a) -> b) -> Dict { } fn do_map( - self: AList, + self: Pairs, with: fn(ByteArray, a) -> b, -) -> AList { +) -> Pairs { when self is { [] -> [] @@ -879,20 +879,20 @@ test map_2() { /// |> dict.insert("a", 100) /// |> dict.insert("b", 200) /// |> dict.insert("c", 300) -/// |> dict.to_list() +/// |> dict.to_pairs() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` -pub fn to_list(self: Dict) -> AList { +pub fn to_pairs(self: Dict) -> Pairs { self.inner } test to_list_1() { - to_list(new()) == [] + to_pairs(new()) == [] } test to_list_2() { - to_list(fixture_1()) == [Pair(bar, 14), Pair(foo, 42)] + to_pairs(fixture_1()) == [Pair(bar, 14), Pair(foo, 42)] } /// Return the number of key-value pairs in the dictionary. @@ -911,7 +911,7 @@ pub fn size(self: Dict) -> Int { do_size(self.inner) } -fn do_size(self: AList) -> Int { +fn do_size(self: Pairs) -> Int { when self is { [] -> 0 [_, ..rest] -> 1 + do_size(rest) @@ -941,11 +941,11 @@ test size_3() { /// right dictionary, values from the left are preferred (i.e. left-biaised). /// /// ```aiken -/// let left_dict = dict.from_list([Pair("a", 100), Pair("b", 200)]) -/// let right_dict = dict.from_list([Pair("a", 150), Pair("c", 300)]) +/// let left_dict = dict.from_pairs([Pair("a", 100), Pair("b", 200)]) +/// let right_dict = dict.from_pairs([Pair("a", 150), Pair("c", 300)]) /// /// let result = -/// dict.union(left_dict, right_dict) |> dict.to_list() +/// dict.union(left_dict, right_dict) |> dict.to_pairs() /// /// result == [Pair("a", 100), Pair("b", 200), Pair("c", 300)] /// ``` @@ -957,9 +957,9 @@ pub fn union( } fn do_union( - left: AList, - right: AList, -) -> AList { + left: Pairs, + right: Pairs, +) -> Pairs { when left is { [] -> right [Pair(k, v), ..rest] -> do_union(rest, do_insert(right, k, v)) @@ -982,7 +982,7 @@ test union_3() { new() |> insert(bar, 42) |> insert(baz, 1337) - union(left, right) == from_list( + union(left, right) == from_pairs( [Pair(foo, 14), Pair(baz, 1337), Pair(bar, 42)], ) } @@ -995,7 +995,7 @@ test union_4() { new() |> insert(bar, 42) |> insert(foo, 1337) - union(left, right) == from_list([Pair(foo, 14), Pair(bar, 42)]) + union(left, right) == from_pairs([Pair(foo, 14), Pair(bar, 42)]) } /// Like [`union`](#union) but allows specifying the behavior to adopt when a key is present @@ -1005,8 +1005,8 @@ test union_4() { /// When passing `None`, the value is removed and not present in the union. /// /// ```aiken -/// let left_dict = dict.from_list([Pair("a", 100), Pair("b", 200)]) -/// let right_dict = dict.from_list([Pair("a", 150), Pair("c", 300)]) +/// let left_dict = dict.from_pairs([Pair("a", 100), Pair("b", 200)]) +/// let right_dict = dict.from_pairs([Pair("a", 150), Pair("c", 300)]) /// /// let result = /// dict.union_with( @@ -1014,7 +1014,7 @@ test union_4() { /// right_dict, /// fn(_k, v1, v2) { Some(v1 + v2) }, /// ) -/// |> dict.to_list() +/// |> dict.to_pairs() /// /// result == [Pair("a", 250), Pair("b", 200), Pair("c", 300)] /// ``` @@ -1027,10 +1027,10 @@ pub fn union_with( } fn do_union_with( - left: AList, - right: AList, + left: Pairs, + right: Pairs, with: fn(ByteArray, value, value) -> Option, -) -> AList { +) -> Pairs { when left is { [] -> right [Pair(k, v), ..rest] -> @@ -1039,11 +1039,11 @@ fn do_union_with( } fn do_insert_with( - self: AList, + self: Pairs, key k: ByteArray, value v: value, with: fn(ByteArray, value, value) -> Option, -) -> AList { +) -> Pairs { when self is { [] -> [Pair(k, v)] @@ -1076,7 +1076,7 @@ test union_with_1() { let result = union_with(left, right, with: fn(_, l, r) { Some(l + r) }) - result == from_list([Pair(foo, 1351), Pair(bar, 42)]) + result == from_pairs([Pair(foo, 1351), Pair(bar, 42)]) } /// Extract all the values present in a given `Dict`. @@ -1095,7 +1095,7 @@ pub fn values(self: Dict) -> List { do_values(self.inner) } -fn do_values(self: AList) -> List { +fn do_values(self: Pairs) -> List { when self is { [] -> [] diff --git a/lib/aiken/associative_list.ak b/lib/aiken/pairs.ak similarity index 89% rename from lib/aiken/associative_list.ak rename to lib/aiken/pairs.ak index 925f479..61849db 100644 --- a/lib/aiken/associative_list.ak +++ b/lib/aiken/pairs.ak @@ -1,7 +1,7 @@ -//// A module for working with associative lists (a.k.a `AList`). +//// A module for working with associative lists (a.k.a `Pairs`). //// -//// While any function that works on `List` also work on `AList`, this module provides some extra helpers -//// that are specifically tailored to working with associative lists. Fundamentally, an `AList` is +//// While any function that works on `List` also work on `Pairs`, this module provides some extra helpers +//// that are specifically tailored to working with associative lists. Fundamentally, a `Pairs` is //// a type-alias to `List>`. //// //// ### Important @@ -10,10 +10,9 @@ //// about the ordering of elements within the list. As a result, lookup //// functions do traverse the entire list when invoked. They are also not _sets_, //// and thus allow for duplicate keys. This is reflected in the functions used +//// to interact with them. -//to interact with them. - -/// Remove a single key-value pair from the AList. If the key is not found, no changes are made. +/// Remove a single key-value pair from the `Pairs`. If the key is not found, no changes are made. /// Duplicate keys are not removed. Only the **first** key found is removed. /// /// ```aiken @@ -22,7 +21,7 @@ /// alist.remove_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] /// alist.remove_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)] /// ``` -pub fn remove_first(self: AList, key k: key) -> AList { +pub fn remove_first(self: Pairs, key k: key) -> Pairs { when self is { [] -> [] @@ -55,7 +54,7 @@ test remove_first_4() { remove_first(fixture, "a") == [Pair("b", 2), Pair("a", 3)] } -/// Remove a single key-value pair from the AList. If the key is not found, no changes are made. +/// Remove a single key-value pair from the Pairs. If the key is not found, no changes are made. /// Duplicate keys are not removed. Only the **last** key found is removed. /// /// ```aiken @@ -64,7 +63,7 @@ test remove_first_4() { /// alist.remove_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] /// alist.remove_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)] /// ``` -pub fn remove_last(self: AList, key k: key) -> AList { +pub fn remove_last(self: Pairs, key k: key) -> Pairs { when self is { [] -> [] @@ -102,7 +101,7 @@ test remove_last_4() { remove_last(fixture, "a") == [Pair("a", 1), Pair("b", 2)] } -/// Remove all key-value pairs matching the key from the AList. If the key is not found, no changes are made. +/// Remove all key-value pairs matching the key from the Pairs. If the key is not found, no changes are made. /// /// ```aiken /// alist.remove_all([], "a") == [] @@ -110,7 +109,7 @@ test remove_last_4() { /// alist.remove_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] /// alist.remove_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)] /// ``` -pub fn remove_all(self: AList, key k: key) -> AList { +pub fn remove_all(self: Pairs, key k: key) -> Pairs { when self is { [] -> [] @@ -151,7 +150,7 @@ test remove_all_4() { /// alist.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a") /// alist.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a") /// ``` -pub fn find_first(self: AList, v: value) -> Option { +pub fn find_first(self: Pairs, v: value) -> Option { when self is { [] -> None [Pair(k2, v2), ..rest] -> @@ -187,7 +186,7 @@ test find_first_4() { /// alist.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a") /// alist.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c") /// ``` -pub fn find_last(self: AList, v: value) -> Option { +pub fn find_last(self: Pairs, v: value) -> Option { when self is { [] -> None [Pair(k2, v2), ..rest] -> @@ -226,7 +225,7 @@ test find_last_4() { /// alist.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"] /// alist.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"] /// ``` -pub fn find_all(self: AList, v: value) -> List { +pub fn find_all(self: Pairs, v: value) -> List { when self is { [] -> [] @@ -255,8 +254,8 @@ test find_all_4() { find_all([Pair("a", 14), Pair("b", 42), Pair("c", 14)], 14) == ["a", "c"] } -/// Fold over the key-value pairs in a AList. The fold direction follows the -/// order of elements in the AList and is done from right-to-left. +/// Fold over the key-value pairs in a Pairs. The fold direction follows the +/// order of elements in the Pairs and is done from right-to-left. /// /// ```aiken /// let fixture = [ @@ -268,7 +267,7 @@ test find_all_4() { /// alist.foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldr( - self: AList, + self: Pairs, zero: result, with: fn(key, value, result) -> result, ) -> result { @@ -310,7 +309,7 @@ test foldr_3() { /// alist.foldl(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldl( - self: AList, + self: Pairs, zero: result, with: fn(key, value, result) -> result, ) -> result { @@ -341,7 +340,7 @@ test foldl_2() { /// alist.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) /// alist.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) /// ``` -pub fn get_first(self: AList, key k: key) -> Option { +pub fn get_first(self: Pairs, key k: key) -> Option { when self is { [] -> None [Pair(k2, v), ..rest] -> @@ -382,7 +381,7 @@ test get_first_5() { /// alist.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) /// alist.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) /// ``` -pub fn get_last(self: AList, key k: key) -> Option { +pub fn get_last(self: Pairs, key k: key) -> Option { when self is { [] -> None [Pair(k2, v), ..rest] -> @@ -425,7 +424,7 @@ test get_last_5() { /// alist.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] /// alist.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] /// ``` -pub fn get_all(self: AList, key k: key) -> List { +pub fn get_all(self: Pairs, key k: key) -> List { when self is { [] -> [] @@ -466,7 +465,7 @@ test get_all_5() { /// alist.has_key([Pair("a", 1), Pair("b", 2)], "a") == True /// alist.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True /// ``` -pub fn has_key(self: AList, k: key) -> Bool { +pub fn has_key(self: Pairs, k: key) -> Bool { when self is { [] -> False // || is lazy so this is fine @@ -494,7 +493,7 @@ test has_key_5() { has_key([Pair("a", 14), Pair("b", 42), Pair("a", 42)], "a") } -/// Extract all the keys present in a given `AList`. +/// Extract all the keys present in a given `Pairs`. /// /// ```aiken /// alist.keys([]) == [] @@ -502,7 +501,7 @@ test has_key_5() { /// alist.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"] /// alist.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"] /// ``` -pub fn keys(self: AList) -> List { +pub fn keys(self: Pairs) -> List { when self is { [] -> [] @@ -531,9 +530,9 @@ test keys_3() { /// alist.map(fixture, fn(_k, v) { v * 2 }) == [Pair("a", 200), Pair("b", 400)] /// ``` pub fn map( - self: AList, + self: Pairs, with: fn(key, value) -> result, -) -> AList { +) -> Pairs { when self is { [] -> [] @@ -556,7 +555,7 @@ test map_2() { map(fixture, with: fn(_, v) { v + 1 }) == [Pair("a", 2), Pair("b", 3)] } -/// Extract all the values present in a given `AList`. +/// Extract all the values present in a given `Pairs`. /// /// ```aiken /// alist.values([]) == [] @@ -564,7 +563,7 @@ test map_2() { /// alist.values([Pair("a", 1), Pair("b", 2)]) == [1, 2] /// alist.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] /// ``` -pub fn values(self: AList) -> List { +pub fn values(self: Pairs) -> List { when self is { [] -> [] diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index 33f4033..defad5b 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -59,10 +59,10 @@ pub type Transaction { fee: Value, mint: MintedValue, certificates: List, - withdrawals: AList, + withdrawals: Pairs, validity_range: ValidityRange, extra_signatories: List>, - redeemers: AList, + redeemers: Pairs, datums: Dict, Data>, id: TransactionId, } @@ -191,7 +191,7 @@ pub fn find_datum( InlineDatum(data) -> if blake2b_256(builtin.serialise_data(data)) == datum_hash{ - + Some(data) } else { None diff --git a/lib/aiken/transaction/value.ak b/lib/aiken/transaction/value.ak index a2e65c0..eac2203 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/aiken/transaction/value.ak @@ -1,4 +1,4 @@ -use aiken/dict.{Dict, from_ascending_list_with} +use aiken/dict.{Dict, from_ascending_pairs_with} use aiken/hash.{Blake2b_224, Hash} use aiken/list use aiken/option @@ -230,7 +230,7 @@ pub fn add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_list([Pair(asset_name, quantity)]), + dict.from_ascending_pairs([Pair(asset_name, quantity)]), helper, ), ) @@ -436,14 +436,14 @@ test reduce_3() { /// /// This function is meant to turn arbitrary user-defined `Data` into safe `Value`, /// while checking for internal invariants. -pub fn from_asset_list(xs: AList>) -> Value { +pub fn from_asset_list(xs: Pairs>) -> Value { xs |> list.foldr( dict.new(), fn(inner, acc) { expect Pair(p, [_, ..] as x) = inner x - |> from_ascending_list_with(fn(v) { v != 0 }) + |> from_ascending_pairs_with(fn(v) { v != 0 }) |> dict.insert_with( acc, p, @@ -633,7 +633,7 @@ pub fn to_minted_value(self: Value) -> MintedValue { test to_minted_value_1() { let minted_value = to_minted_value(zero()) - ( minted_value.inner |> dict.to_list |> list.length ) == 1 + ( minted_value.inner |> dict.to_pairs |> list.length ) == 1 } test to_minted_value_2() { @@ -670,7 +670,7 @@ fn unchecked_add( dict.insert_with( self.inner, policy_id, - dict.from_ascending_list([Pair(asset_name, quantity)]), + dict.from_ascending_pairs([Pair(asset_name, quantity)]), fn(_, left, _right) { Some( dict.insert_with( From cfcf2bfbdd6c8f3f6fde3492467b9b01a86c6c6b Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 23 May 2024 16:27:54 -0400 Subject: [PATCH 37/45] fix formatting issue --- lib/aiken/transaction.ak | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index defad5b..eb1572e 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -191,7 +191,7 @@ pub fn find_datum( InlineDatum(data) -> if blake2b_256(builtin.serialise_data(data)) == datum_hash{ - + Some(data) } else { None From c94606a256d4cd18b67e2bcd6cee16d2a2203ea5 Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 23 May 2024 22:43:30 -0400 Subject: [PATCH 38/45] new ci version of aiken --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 12e257f..acfc775 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -33,7 +33,7 @@ jobs: - name: 🧰 Install Aiken uses: aiken-lang/setup-aiken@v0.1.0 with: - version: v1.0.26-alpha + version: v1.0.28-alpha - name: 📝 Run fmt run: aiken fmt --check From 93f170504d6e4b336302e961a14605621bbe3519 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 24 May 2024 09:33:56 +0200 Subject: [PATCH 39/45] Bump setup-aiken. --- .github/workflows/continuous-integration.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index acfc775..29d6f49 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -31,7 +31,7 @@ jobs: uses: actions/configure-pages@v2 - name: 🧰 Install Aiken - uses: aiken-lang/setup-aiken@v0.1.0 + uses: aiken-lang/setup-aiken@v1 with: version: v1.0.28-alpha From de654c43c2949f4a4b6738772547cc60a077fc2d Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 24 May 2024 10:12:22 +0200 Subject: [PATCH 40/45] Add small 'compatibility matrix' on README. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 8e5d060..b3a4c5f 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,15 @@
+## Compatibility + +aiken's version | stdlib's version(s) +--- | --- +`v1.0.28-alpha` | `1.9.0` +`v1.0.26-alpha` | `1.8.0` + +## Overview + The official standard library for the [Aiken](https://aiken-lang.org) Cardano smart-contract language. From b83d3c34e39a3535ab97b0628cc011881b4ef751 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 24 May 2024 10:14:03 +0200 Subject: [PATCH 41/45] Bump version to 1.9.0 --- CHANGELOG.md | 2 +- aiken.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb8090a..2bec225 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## v1.9.0 - UNRELEASED +## v1.9.0 - 2024-05-24 ### Added diff --git a/aiken.toml b/aiken.toml index af339e7..5d5dc77 100644 --- a/aiken.toml +++ b/aiken.toml @@ -1,5 +1,5 @@ name = "aiken-lang/stdlib" -version = "1.8.0" +version = "1.9.0" licences = ["Apache-2.0"] description = "The Aiken Standard Library" From 18a630559725ce730eb35dcd7b0f31b98baca3e0 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 24 May 2024 11:17:44 +0200 Subject: [PATCH 42/45] Fix documentation examples on pairs. --- .github/workflows/continuous-integration.yml | 2 +- lib/aiken/pairs.ak | 106 +++++++++---------- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 29d6f49..399db4d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -52,7 +52,7 @@ jobs: path: "docs/" deploy: - if: ${{ startsWith(github.ref, 'refs/tags') }} + # if: ${{ startsWith(github.ref, 'refs/tags') }} needs: build runs-on: ubuntu-latest environment: diff --git a/lib/aiken/pairs.ak b/lib/aiken/pairs.ak index 61849db..dd67f56 100644 --- a/lib/aiken/pairs.ak +++ b/lib/aiken/pairs.ak @@ -16,10 +16,10 @@ /// Duplicate keys are not removed. Only the **first** key found is removed. /// /// ```aiken -/// alist.remove_first([], "a") == [] -/// alist.remove_first([Pair("a", 1)], "a") == [] -/// alist.remove_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] -/// alist.remove_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)] +/// pairs.remove_first([], "a") == [] +/// pairs.remove_first([Pair("a", 1)], "a") == [] +/// pairs.remove_first([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// pairs.remove_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2), Pair("a", 3)] /// ``` pub fn remove_first(self: Pairs, key k: key) -> Pairs { when self is { @@ -58,10 +58,10 @@ test remove_first_4() { /// Duplicate keys are not removed. Only the **last** key found is removed. /// /// ```aiken -/// alist.remove_last([], "a") == [] -/// alist.remove_last([Pair("a", 1)], "a") == [] -/// alist.remove_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] -/// alist.remove_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)] +/// pairs.remove_last([], "a") == [] +/// pairs.remove_last([Pair("a", 1)], "a") == [] +/// pairs.remove_last([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// pairs.remove_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("a", 1), Pair("b", 2)] /// ``` pub fn remove_last(self: Pairs, key k: key) -> Pairs { when self is { @@ -104,10 +104,10 @@ test remove_last_4() { /// Remove all key-value pairs matching the key from the Pairs. If the key is not found, no changes are made. /// /// ```aiken -/// alist.remove_all([], "a") == [] -/// alist.remove_all([Pair("a", 1)], "a") == [] -/// alist.remove_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] -/// alist.remove_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)] +/// pairs.remove_all([], "a") == [] +/// pairs.remove_all([Pair("a", 1)], "a") == [] +/// pairs.remove_all([Pair("a", 1), Pair("b", 2)], "a") == [Pair("b", 2)] +/// pairs.remove_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [Pair("b", 2)] /// ``` pub fn remove_all(self: Pairs, key k: key) -> Pairs { when self is { @@ -145,10 +145,10 @@ test remove_all_4() { /// Finds the first key in the alist associated with a given value, if any. /// /// ```aiken -/// alist.find_first([], 1) == None -/// alist.find_first([Pair("a", 1)], 1) == Some("a") -/// alist.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a") -/// alist.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a") +/// pairs.find_first([], 1) == None +/// pairs.find_first([Pair("a", 1)], 1) == Some("a") +/// pairs.find_first([Pair("a", 1), Pair("b", 2)], 1) == Some("a") +/// pairs.find_first([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("a") /// ``` pub fn find_first(self: Pairs, v: value) -> Option { when self is { @@ -181,10 +181,10 @@ test find_first_4() { /// Finds the last key in the alist associated with a given value, if any. /// /// ```aiken -/// alist.find_last([], 1) == None -/// alist.find_last([Pair("a", 1)], 1) == Some("a") -/// alist.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a") -/// alist.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c") +/// pairs.find_last([], 1) == None +/// pairs.find_last([Pair("a", 1)], 1) == Some("a") +/// pairs.find_last([Pair("a", 1), Pair("b", 2)], 1) == Some("a") +/// pairs.find_last([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == Some("c") /// ``` pub fn find_last(self: Pairs, v: value) -> Option { when self is { @@ -220,10 +220,10 @@ test find_last_4() { /// Finds all keys in the alist associated with a given value. /// /// ```aiken -/// alist.find_all([], 1) == [] -/// alist.find_all([Pair("a", 1)], 1) == ["a"] -/// alist.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"] -/// alist.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"] +/// pairs.find_all([], 1) == [] +/// pairs.find_all([Pair("a", 1)], 1) == ["a"] +/// pairs.find_all([Pair("a", 1), Pair("b", 2)], 1) == ["a"] +/// pairs.find_all([Pair("a", 1), Pair("b", 2), Pair("c", 1)], 1) == ["a", "c"] /// ``` pub fn find_all(self: Pairs, v: value) -> List { when self is { @@ -264,7 +264,7 @@ test find_all_4() { /// Pair(3, 300), /// ] /// -/// alist.foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 +/// pairs.foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldr( self: Pairs, @@ -296,7 +296,7 @@ test foldr_3() { foldr(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 } -/// Fold over the key-value pairs in a alist. The fold direction follows keys +/// Fold over the key-value pairs in a pairs. The fold direction follows keys /// in ascending order and is done from left-to-right. /// /// ```aiken @@ -306,7 +306,7 @@ test foldr_3() { /// Pair(3, 300), /// ] /// -/// alist.foldl(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 +/// pairs.foldl(fixture, 0, fn(k, v, result) { k * v + result }) == 1400 /// ``` pub fn foldl( self: Pairs, @@ -335,10 +335,10 @@ test foldl_2() { /// If multiple values with the same key exist, only the first one is returned. /// /// ```aiken -/// alist.get_first([], "a") == None -/// alist.get_first([Pair("a", 1)], "a") == Some(1) -/// alist.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) -/// alist.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) +/// pairs.get_first([], "a") == None +/// pairs.get_first([Pair("a", 1)], "a") == Some(1) +/// pairs.get_first([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +/// pairs.get_first([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(1) /// ``` pub fn get_first(self: Pairs, key k: key) -> Option { when self is { @@ -376,10 +376,10 @@ test get_first_5() { /// If multiple values with the same key exist, only the last one is returned. /// /// ```aiken -/// alist.get_last([], "a") == None -/// alist.get_last([Pair("a", 1)], "a") == Some(1) -/// alist.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) -/// alist.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) +/// pairs.get_last([], "a") == None +/// pairs.get_last([Pair("a", 1)], "a") == Some(1) +/// pairs.get_last([Pair("a", 1), Pair("b", 2)], "a") == Some(1) +/// pairs.get_last([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == Some(3) /// ``` pub fn get_last(self: Pairs, key k: key) -> Option { when self is { @@ -419,10 +419,10 @@ test get_last_5() { /// Get all values in the alist associated with a given key. /// /// ```aiken -/// alist.get_all([], "a") == [] -/// alist.get_all([Pair("a", 1)], "a") == [1] -/// alist.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] -/// alist.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] +/// pairs.get_all([], "a") == [] +/// pairs.get_all([Pair("a", 1)], "a") == [1] +/// pairs.get_all([Pair("a", 1), Pair("b", 2)], "a") == [1] +/// pairs.get_all([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == [1, 3] /// ``` pub fn get_all(self: Pairs, key k: key) -> List { when self is { @@ -457,13 +457,13 @@ test get_all_5() { get_all([Pair("a", 1), Pair("b", 2), Pair("c", 3)], "d") == [] } -/// Check if a key exists in the alist. +/// Check if a key exists in the pairs. /// /// ```aiken -/// alist.has_key([], "a") == False -/// alist.has_key([Pair("a", 1)], "a") == True -/// alist.has_key([Pair("a", 1), Pair("b", 2)], "a") == True -/// alist.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True +/// pairs.has_key([], "a") == False +/// pairs.has_key([Pair("a", 1)], "a") == True +/// pairs.has_key([Pair("a", 1), Pair("b", 2)], "a") == True +/// pairs.has_key([Pair("a", 1), Pair("b", 2), Pair("a", 3)], "a") == True /// ``` pub fn has_key(self: Pairs, k: key) -> Bool { when self is { @@ -496,10 +496,10 @@ test has_key_5() { /// Extract all the keys present in a given `Pairs`. /// /// ```aiken -/// alist.keys([]) == [] -/// alist.keys([Pair("a", 1)]) == ["a"] -/// alist.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"] -/// alist.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"] +/// pairs.keys([]) == [] +/// pairs.keys([Pair("a", 1)]) == ["a"] +/// pairs.keys([Pair("a", 1), Pair("b", 2)]) == ["a", "b"] +/// pairs.keys([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == ["a", "b", "a"] /// ``` pub fn keys(self: Pairs) -> List { when self is { @@ -527,7 +527,7 @@ test keys_3() { /// ```aiken /// let fixture = [Pair("a", 100), Pair("b", 200)] /// -/// alist.map(fixture, fn(_k, v) { v * 2 }) == [Pair("a", 200), Pair("b", 400)] +/// pairs.map(fixture, fn(_k, v) { v * 2 }) == [Pair("a", 200), Pair("b", 400)] /// ``` pub fn map( self: Pairs, @@ -558,10 +558,10 @@ test map_2() { /// Extract all the values present in a given `Pairs`. /// /// ```aiken -/// alist.values([]) == [] -/// alist.values([Pair("a", 1)]) == [1] -/// alist.values([Pair("a", 1), Pair("b", 2)]) == [1, 2] -/// alist.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] +/// pairs.values([]) == [] +/// pairs.values([Pair("a", 1)]) == [1] +/// pairs.values([Pair("a", 1), Pair("b", 2)]) == [1, 2] +/// pairs.values([Pair("a", 1), Pair("b", 2), Pair("a", 3)]) == [1, 2, 3] /// ``` pub fn values(self: Pairs) -> List { when self is { From 0407b3a17518479e98ba2e2558fadee1070309bb Mon Sep 17 00:00:00 2001 From: KtorZ Date: Thu, 6 Jun 2024 11:29:46 +0200 Subject: [PATCH 43/45] Update stdlib's compatibility matrix. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b3a4c5f..a33bf3f 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,9 @@ aiken's version | stdlib's version(s) --- | --- -`v1.0.28-alpha` | `1.9.0` -`v1.0.26-alpha` | `1.8.0` +`v1.0.29-alpha` | `>= 1.9.0` +`v1.0.28-alpha` | `>= 1.9.0` +`v1.0.26-alpha` | `<= 1.8.0` ## Overview From 1522f63b886062a865c4f189878304924096730e Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Mon, 24 Jun 2024 12:41:11 -0700 Subject: [PATCH 44/45] split scriptpurpose into scriptinfo, update names, and change scriptcontext --- lib/aiken/transaction.ak | 42 +++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index 47f6a08..bbcf03f 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -24,7 +24,39 @@ use aiken/transaction/value.{Lovelace, PolicyId, Value} /// being executed. pub type ScriptContext { transaction: Transaction, - purpose: ScriptPurpose, + redeemer: Redeemer, + info: ScriptInfo, +} + +/// Characterizes the kind of script being executed. +pub type ScriptInfo { + /// For scripts executed as minting/burning policies, to insert + /// or remove assets from circulation. It's parameterized by the identifier + /// of the associated policy. + Minting(PolicyId) + /// For scripts that are used as payment credentials for addresses in + /// transaction outputs. They govern the rule by which the output they + /// reference can be spent. + Spending(OutputReference, Option) + /// For scripts that validate reward withdrawals from a reward account. + /// + /// The argument identifies the target reward account. + Withdrawing(StakeCredential) + /// Needed when delegating to a pool using stake credentials defined as a + /// Plutus script. This purpose is also triggered when de-registering such + /// stake credentials. + /// + /// The Int is a 0-based index of the given `TxCert` in `certificates`. + Publishing(Int, Certificate) + /// Voting for a type of voter using a governance action id to vote + /// yes / no / abstain inside a transaction. + /// + /// The voter is who is doing the governance action. + Voting(Voter) + /// Used to propose a governance action. + /// + /// A 0-based index of the given `ProposalProcedure` in `proposal_procedures`. + Proposing(Int, ProposalProcedure) } /// Characterizes the kind of script being executed. @@ -40,22 +72,22 @@ pub type ScriptPurpose { /// For scripts that validate reward withdrawals from a reward account. /// /// The argument identifies the target reward account. - WithdrawFrom(StakeCredential) + Withdraw(StakeCredential) /// Needed when delegating to a pool using stake credentials defined as a /// Plutus script. This purpose is also triggered when de-registering such /// stake credentials. /// /// The Int is a 0-based index of the given `TxCert` in `certificates`. - Publish { certificate_index: Int, certificate: Certificate } + Publish(Int, Certificate) /// Voting for a type of voter using a governance action id to vote /// yes / no / abstain inside a transaction. /// /// The voter is who is doing the governance action. - Voting(Voter) + Vote(Voter) /// Used to propose a governance action. /// /// A 0-based index of the given `ProposalProcedure` in `proposal_procedures`. - Proposing { proposal_index: Int, proposal: ProposalProcedure } + Propose(Int, ProposalProcedure) } /// A Cardano `Transaction`, as seen by Plutus scripts. From 8ae154a9d9ca6a96c1cffa4c8df7939e2058f9e5 Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Mon, 24 Jun 2024 12:45:24 -0700 Subject: [PATCH 45/45] merge this up into the v3 branch --- lib/aiken/transaction.ak | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/aiken/transaction.ak b/lib/aiken/transaction.ak index bbcf03f..ae39477 100644 --- a/lib/aiken/transaction.ak +++ b/lib/aiken/transaction.ak @@ -19,7 +19,7 @@ use aiken/transaction/value.{Lovelace, PolicyId, Value} /// /// The context contains information about the entire transaction that contains /// the script. The transaction may also contain other scripts; to distinguish -/// between multiple scripts, the `ScriptContext` also contains a `purpose` +/// between multiple scripts, the `ScriptInfo` contains a `purpose` /// which indicates which script (or, for what purpose) of the transaction is /// being executed. pub type ScriptContext { @@ -28,7 +28,7 @@ pub type ScriptContext { info: ScriptInfo, } -/// Characterizes the kind of script being executed. +/// Characterizes the script information. pub type ScriptInfo { /// For scripts executed as minting/burning policies, to insert /// or remove assets from circulation. It's parameterized by the identifier @@ -59,7 +59,7 @@ pub type ScriptInfo { Proposing(Int, ProposalProcedure) } -/// Characterizes the kind of script being executed. +/// Characterizes the script purpose. pub type ScriptPurpose { /// For scripts executed as minting/burning policies, to insert /// or remove assets from circulation. It's parameterized by the identifier @@ -109,9 +109,10 @@ pub type Transaction { validity_range: ValidityRange, extra_signatories: List, redeemers: Pairs, + // ^ Pairs and ScriptPurpose are used here datums: Dict, id: TransactionId, - // all new fields below for v3 + // new fields for v3 votes: Dict>, proposal_procedures: List, current_treasury_amount: Option,