From 3029bf31cb0b1d9f6e67d228691500c525895c91 Mon Sep 17 00:00:00 2001 From: Gaith Hallak Date: Sat, 7 Aug 2021 11:08:45 +0300 Subject: [PATCH] Implement `Set` stdlib (#335) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement Set stdlib * Rename an argument of the function Set.fold * Add docs for Set stdlib * Correct the usage of articles in the docs * Fix bug * Fix the link to Set stdlib section Co-authored-by: Radosław Rowicki <35342116+radrow@users.noreply.github.com> --- CHANGELOG.md | 1 + docs/sophia_stdlib.md | 123 ++++++++++++++++++++++++++++++++++++++++++ priv/stdlib/Set.aes | 51 ++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 priv/stdlib/Set.aes diff --git a/CHANGELOG.md b/CHANGELOG.md index da4200e..f5f6ee0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- `Set` stdlib - `Option.force_msg` ### Changed ### Removed diff --git a/docs/sophia_stdlib.md b/docs/sophia_stdlib.md index b9c8521..9a9ed5a 100644 --- a/docs/sophia_stdlib.md +++ b/docs/sophia_stdlib.md @@ -39,6 +39,7 @@ include "List.aes" - [Triple](#Triple) - [BLS12_381](#BLS12_381) - [Frac](#Frac) +- [Set](#set-stdlib) # Builtin namespaces @@ -2274,3 +2275,125 @@ accept arbitrary `frac`s from the surface you should report it as a If you expect getting calls with malformed `frac`s in your contract, you should use this function to verify the input. + +## Set + +### Types + +``` +record set('a) = { to_map : map('a, unit) } +``` + +### Functions + +#### new + +``` +Set.new() : set('a) +``` + +Returns an empty set + +#### member + +``` +member(e : 'a, s : set('a)) : bool +``` + +Checks if the element `e` is present in the set `s` + +#### insert + +``` +insert(e : 'a, s : set('a)) : set('a) +``` + +Inserts the element `e` in the set `s` + +#### delete + +``` +Set.delete(e : 'a, s : set('a)) : set('a) +``` + +Removes the element `e` from the set `s` + +#### size + +``` +size(s : set('a)) : int +``` + +Returns the number of elements in the set `s` + +#### to_list + +``` +Set.to_list(s : set('a)) : list('a) +``` + +Returns a list containing the elements of the set `s` + +#### from_list + +``` +Set.from_list(l : list('a)) : set('a) +``` + +Turns the list `l` into a set + +#### filter + +``` +Set.filter(p : 'a => bool, s : set('a)) : set('a) +``` + +Filters out elements of `s` that fulfill predicate `p` + +#### fold + +``` +Set.fold(f : ('a, 'b) => 'b, acc : 'b, s : set('a)) : 'b +``` + +Folds the function `f` over every element in the set `s` and returns the final value of the accumulator `acc`. + +#### subtract + +``` +Set.subtract(s1 : set('a), s2 : set('a)) : set('a) +``` + +Returns the elements of `s1` that are not members of `s2` + +#### intersection + +``` +Set.intersection(s1 : set('a), s2 : set('a)) : set('a) +``` + +Returns the intersection of the two sets `s1` and `s2` + +#### intersection_list + +``` +Set.intersection_list(sets : list(set('a))) : set('a) +``` + +Returns the intersection of all the sets in the given list + +#### union + +``` +Set.union(s1 : set('a), s2 : set('a)) : set('a) +``` + +Returns the union of the two sets `s1` and `s2` + +#### union_list + +``` +Set.union_list(sets : list(set('a))) : set('a) +``` + +Returns the union of all the sets in the given list diff --git a/priv/stdlib/Set.aes b/priv/stdlib/Set.aes new file mode 100644 index 0000000..daec288 --- /dev/null +++ b/priv/stdlib/Set.aes @@ -0,0 +1,51 @@ +include "List.aes" +include "Option.aes" +include "Pair.aes" + +namespace Set = + record set('a) = { to_map : map('a, unit) } + + function new() : set('a) = + { to_map = {} } + + function member(e : 'a, s : set('a)) : bool = + Map.member(e, s.to_map) + + function insert(e : 'a, s : set('a)) : set('a) = + { to_map = s.to_map{[e] = ()} } + + function delete(e : 'a, s : set('a)) : set('a) = + { to_map = Map.delete(e, s.to_map) } + + function size(s : set('a)) : int = + Map.size(s.to_map) + + function to_list(s : set('a)) : list('a) = + List.map(Pair.fst, Map.to_list(s.to_map)) + + function from_list(l : list('a)) : set('a) = + { to_map = Map.from_list(List.map((x) => (x, ()), l)) } + + function filter(p : 'a => bool, s : set('a)) : set('a) = + from_list(List.filter(p, to_list(s))) + + function fold(f : ('a, 'b) => 'b, acc : 'b, s : set('a)) : 'b = + List.foldr(f, acc, to_list(s)) + + function subtract(s1 : set('a), s2 : set('a)) : set('a) = + filter((x) => !member(x, s2), s1) + + function intersection(s1 : set('a), s2 : set('a)) : set('a) = + filter((x) => member(x, s2), s1) + + function intersection_list(sets : list(set('a))) : set('a) = + List.foldr( + intersection, + Option.default(new(), List.first(sets)), + Option.default([], List.tail(sets))) + + function union(s1 : set('a), s2 : set('a)) : set('a) = + from_list(to_list(s1) ++ to_list(s2)) + + function union_list(sets : list(set('a))) : set('a) = + List.foldr(union, new(), sets)