From 4ded06d2395e7ba3019ceaa01ad7ed96c47ac8db Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 27 May 2022 11:15:45 +0100 Subject: [PATCH 1/4] modified my non-empty contributions to remove (hopefully) scala 2.13 dependency --- .../main/scala/zio/prelude/NonEmptyMap.scala | 227 +++++++++++++++ .../main/scala/zio/prelude/NonEmptySet.scala | 9 + .../scala/zio/prelude/NonEmptySortedMap.scala | 196 +++++++++++++ .../scala/zio/prelude/NonEmptySortedSet.scala | 264 ++++++++++++++++++ 4 files changed, 696 insertions(+) create mode 100644 core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala create mode 100644 core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala create mode 100644 core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala b/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala new file mode 100644 index 000000000..b940da752 --- /dev/null +++ b/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala @@ -0,0 +1,227 @@ +package zio.prelude + +/* + * Copyright 2020-2022 John A. De Goes and the ZIO Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import zio.NonEmptyChunk + +import scala.language.implicitConversions + +/** + * A non-empty wrapper for the scala immutable map. Note - this does not attempt to implement all features of + * map but what the author considers to be the "normal ones". + */ +case class NonEmptyMap[K, V] private(private val map: Map[K, V]) { self => + + private def newMap[V2](map: Map[K, V2]): NonEmptyMap[K,V2] = new NonEmptyMap(map) + + /** Converts this `NonEmptyMap` to a `Map`. */ + def toMap: Map[K, V] = map + + /** + * Returns an element of this `NonEmptyMap` and the remainder, which is a (possibly empty) `Map`. + */ + @inline + def peel: ((K, V), Map[K, V]) = (map.head, map.tail) + + /** + * Returns an element of this `NonEmptyMap` + * and the remainder or `None`, if the remainder is empty. + */ + def peelNonEmpty: ((K, V), Option[NonEmptyMap[K, V]]) = { + val (head, tail) = peel + if (tail.isEmpty) + (head, None) + else + (head, Some(newMap(tail))) + } + + + /** + * Creates a new `NonEmptyMap` with an additional element, unless the element is + * already present. + * + * @param elem the element to be added + * @return a new map that contains all elements of this map and that also + * contains `elem`. + */ + def +(elem: (K,V)): NonEmptyMap[K, V] = newMap(map + elem) + + /** + * Creates a new `NonEmptyMap` by adding all elements contained in another collection to this `NonEmptyMap`, omitting duplicates. + * + * This method takes a collection of elements and adds all elements, omitting duplicates, into `NonEmptyMap`. + * + * Example: + * {{{ + * scala> val a = NonEmptyMap(1, 2) ++ NonEmptyMap(2, "a") + * a: zio.prelude.NonEmptyMap[Any] = NonEmptyMap(1, 2, a) + * }}} + * + * @param elems the collection containing the elements to add. + * @return a new `NonEmptyMap` with the given elements added, omitting duplicates. + */ + def ++(elems: Iterable[(K, V)]): NonEmptyMap[K, V] = newMap(map ++ elems) + + /** Adds the `elem` to this `NonEmptyMap`. Alias for `+`. */ + def add(elem: (K, V)): NonEmptyMap[K, V] = self + elem + + /** Removes the `elem` from this `NonEmptyMap`. Alias for `-`. */ + def remove(elem: K): Map[K, V] = map - elem + + /** + * Returns the tail of this `NonEmptyMap` if it exists or `None` otherwise. + */ + def tailNonEmpty: Option[NonEmptyMap[K, V]] = peelNonEmpty._2 + + /** + * Produces a new non empty map where values mapped according to function f. For compatibility + * does not use map.iew + */ + def mapValues[V1](f: V => V1): NonEmptyMap[K, V1] = { + val newInner = map.map(tup => tup._1 -> f(tup._2)) + newMap(newInner) + } + + override def hashCode: Int = map.hashCode ^ NonEmptyMap.NonEmptyMapSeed + + override def equals(that: Any): Boolean = + that match { + case that: AnyRef if self.eq(that) => true + case that: NonEmptyMap[_, _] => self.map == that.toMap + case _ => false + } + + override def toString: String = s"NonEmpty$map" +} + +object NonEmptyMap { + + def apply[K, V](elem: (K, V), others: Iterable[(K, V)]): NonEmptyMap[K, V] = + new NonEmptyMap(others.toMap + elem) + + /** + * Creates a `NonEmptyMap` with the specified elements. + * @tparam A the type of the `NonEmptyMap`'s elements + * @param elem an element of the created `NonEmptyMap` + * @param others the remaining elements of the created `NonEmptyMap` + * @return a new `NonEmptyMap` with elements `elem` and `others` + */ + def apply[K, V](elem: (K, V), others: (K, V)*): NonEmptyMap[K, V] = apply(elem, others) + + def unapply[K, V](arg: NonEmptyMap[K, V]): Some[((K, V), Map[K, V])] = Some(arg.peel) + + /** + * Constructs a `NonEmptyMap` from a `NonEmptyChunk`. + */ + def fromNonEmptyChunk[K, V](elems: NonEmptyChunk[(K, V)]): NonEmptyMap[K, V] = apply(elems.head, elems.tail) + + /** + * Constructs a `NonEmptyMap` from a `NonEmptyList`. + */ + def fromNonEmptyList[K, V](elems: NonEmptyList[(K, V)]): NonEmptyMap[K, V] = apply(elems.head, elems.tail) + + /** + * Constructs a `NonEmptyMap` from an element and `Map`. + */ + def fromMap[K, V](elem: (K, V), others: Map[K, V]): NonEmptyMap[K, V] = apply(elem, others) + + /** + * Constructs a `NonEmptyMap` from a `Map` or `None` otherwise. + */ + def fromMapOption[K, V](map: Map[K, V]): Option[NonEmptyMap[K, V]] = map.headOption.map(fromMap(_, map.tail)) + + /** + * Constructs a `NonEmptyMap` from an element and `Iterable`. + */ + def fromIterable[K, V](head: (K, V), tail: Iterable[(K, V)]): NonEmptyMap[K, V] = + fromMap(head, tail.toMap) + + /** + * Constructs a `NonEmptyMap` from an `Iterable` or `None` otherwise. + */ + def fromIterableOption[K, V](iterable: Iterable[(K, V)]): Option[NonEmptyMap[K, V]] = + iterable.headOption.fold(None: Option[NonEmptyMap[K, V]])(h => Some(fromIterable(h, iterable.tail))) + + /** + * Constructs a `NonEmptyMap` with the specified single value. + */ + def single[K, V](head: (K, V)): NonEmptyMap[K, V] = + NonEmptyMap(head) + + /** + * Provides an implicit conversion from `NonEmptyMap` to the `Map` + * for interoperability with Scala's collection library. + */ + implicit def toMap[K, V](nonEmptyMap: NonEmptyMap[K, V]): Map[K, V] = + nonEmptyMap.toMap + + private val NonEmptyMapSeed: Int = 1247820194 + + /** + * GroupByOption function returns an option of a nonEmpty map instead of a map because by definition + * the elements will be non-empty - returns None if from is + */ + def groupByOption[A, K](from: Iterable[A])(f: A => K): Option[NonEmptyMap[K, Iterable[A]]] = + from.headOption.map(_ => NonEmptyMap(from.groupBy(f))) + + /** + * from a non-empty chunk we can create a non-empty map of non-empty chunks + */ + def groupByFromNonEmptyChunk[A, K](from: NonEmptyChunk[A])(f: A => K): NonEmptyMap[K, NonEmptyChunk[A]] = { + val gb = from.groupBy(f) + val asChunks =gb.map{ p => (p._1 -> NonEmptyChunk.fromIterableOption(p._2).get) } // safe! + NonEmptyMap(asChunks) + } + + /** + * from a non-empty set we can create a non-empty map of non-empty sets + */ + def groupByFromNonEmptySet[A, K](from: NonEmptySet[A])(f: A => K): NonEmptyMap[K, NonEmptySet[A]] = { + val gb = from.groupBy(f) + val asSets = gb.map { p => (p._1 -> NonEmptySet.fromIterableOption(p._2).get) } // safe! + NonEmptyMap(asSets) + } + + /** + * from a non-empty list we can create a non-empty map of non-empty list + */ + def groupByFromNonEmptyList[A, K](from: NonEmptyList[A])(f: A => K): NonEmptyMap[K, NonEmptyList[A]] = { + val gb = from.groupBy(f) + val asLists = gb.map { p => (p._1 -> NonEmptyList.fromIterableOption(p._2).get) } // safe! + NonEmptyMap(asLists) + } + +} + +trait NonEmptyMapSyntax { + implicit final class NonEmptyMapIterableOps[K, V](private val iterable: Iterable[(K, V)]) { + + /** + * Constructs a `NonEmptyMap` from an `Iterable` or `None` otherwise. + */ + def toNonEmptyMap: Option[NonEmptyMap[K, V]] = NonEmptyMap.fromIterableOption(iterable) + } + implicit final class NonEmptyMapMapOps[K, V](self: Map[K, V]) { + + /** + * Constructs a `NonEmptyMap` from a `Map` or `None` otherwise. + */ + def toNonEmptyMap: Option[NonEmptyMap[K, V]] = NonEmptyMap.fromMapOption(self) + } +} + diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySet.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySet.scala index 32fdc53fc..57b4d0ce4 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptySet.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySet.scala @@ -95,6 +95,15 @@ final class NonEmptySet[A] private (private val set: Set[A]) { self => /** Removes the `elem` from this `NonEmptySet`. Alias for `-`. */ def remove(elem: A): Set[A] = set - elem + /** + * removes the elem from `NonEmptySet`, returning Some(NonEmptySet) if there's anything + * left, otherwise None + */ + def removeNonEmpty(elem: A): Option[NonEmptySet[A]] = { + val newSet = set - elem + if (newSet.nonEmpty) Some(new NonEmptySet(set)) else None + } + /** * Returns the tail of this `NonEmptySet` if it exists or `None` otherwise. */ diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala new file mode 100644 index 000000000..8703ad302 --- /dev/null +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala @@ -0,0 +1,196 @@ +package zio.prelude + +/* + * Copyright 2020-2022 John A. De Goes and the ZIO Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import zio.NonEmptyChunk + +import scala.collection.immutable.SortedMap +import scala.language.implicitConversions +import scala.math.{Ordering => SOrdering} + +/** + * A non-empty wrapper for the scala immutable map. Note - this does not attempt to implement all features of + * map but what the author considers to be the "normal ones". + */ +case class NonEmptySortedMap[K, V] private(private val map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]) { self => + + private def newMap[V2](map: SortedMap[K, V2]): NonEmptySortedMap[K,V2] = new NonEmptySortedMap(map) + + /** Converts this `NonEmptySortedMap` to a `SortedMap`. */ + def toMap: SortedMap[K, V] = map + + /** + * Returns an element of this `NonEmptySortedMap` and the remainder, which is a (possibly empty) `SortedMap`. + */ + @inline + def peel: ((K, V), SortedMap[K, V]) = (map.head, map.tail) + + /** + * Returns an element of this `NonEmptySortedMap` + * and the remainder or `None`, if the remainder is empty. + */ + def peelNonEmpty: ((K, V), Option[NonEmptySortedMap[K, V]]) = { + val (head, tail) = peel + if (tail.isEmpty) + (head, None) + else + (head, Some(newMap(tail))) + } + + + /** + * Creates a new `NonEmptySortedMap` with an additional element, unless the element is + * already present. + * + * @param elem the element to be added + * @return a new map that contains all elements of this map and that also + * contains `elem`. + */ + def +(elem: (K,V)): NonEmptySortedMap[K, V] = newMap(map + elem) + + /** + * Creates a new `NonEmptySortedMap` by adding all elements contained in another collection to this `NonEmptySortedMap`, omitting duplicates. + * + * This method takes a collection of elements and adds all elements, omitting duplicates, into `NonEmptySortedMap`. + * + * Example: + * {{{ + * scala> val a = NonEmptySortedMap(1, 2) ++ NonEmptySortedMap(2, "a") + * a: zio.prelude.NonEmptySortedMap[Any] = NonEmptySortedMap(1, 2, a) + * }}} + * + * @param elems the collection containing the elements to add. + * @return a new `NonEmptySortedMap` with the given elements added, omitting duplicates. + */ + def ++(elems: Iterable[(K, V)]): NonEmptySortedMap[K, V] = newMap(map ++ elems) + + /** Adds the `elem` to this `NonEmptySortedMap`. Alias for `+`. */ + def add(elem: (K, V)): NonEmptySortedMap[K, V] = self + elem + + /** Removes the `elem` from this `NonEmptySortedMap`. Alias for `-`. */ + def remove(elem: K): SortedMap[K, V] = map - elem + + /** + * Returns the tail of this `NonEmptySortedMap` if it exists or `None` otherwise. + */ + def tailNonEmpty: Option[NonEmptySortedMap[K, V]] = peelNonEmpty._2 + + /** + * Produces a new non empty map where values mapped according to function f. + */ + def mapValues[V1](f: V => V1) = { + val newInner = map.map{ p => (p._1, f(p._2))} + newMap(newInner) + } + + override def hashCode: Int = map.hashCode ^ NonEmptySortedMap.NonEmptyMapSeed + + override def equals(that: Any): Boolean = + that match { + case that: AnyRef if self.eq(that) => true + case that: NonEmptySortedMap[_, _] => self.map == that.toMap + case _ => false + } + + override def toString: String = s"NonEmpty$map" +} + +object NonEmptySortedMap { + + def apply[K, V](elem: (K, V), others: Iterable[(K, V)])(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = + new NonEmptySortedMap(SortedMap.from(others.toMap) + elem) + + /** + * Creates a `NonEmptySortedMap` with the specified elements. + * @tparam A the type of the `NonEmptySortedMap`'s elements + * @param elem an element of the created `NonEmptySortedMap` + * @param others the remaining elements of the created `NonEmptySortedMap` + * @return a new `NonEmptySortedMap` with elements `elem` and `others` + */ + def apply[K, V](elem: (K, V), others: (K, V)*)(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = + apply(elem, others) + + def unapply[K, V](arg: NonEmptySortedMap[K, V]): Some[((K, V), SortedMap[K, V])] = Some(arg.peel) + + /** + * Constructs a `NonEmptySortedMap` from a `NonEmptyChunk`. + */ + def fromNonEmptyChunk[K, V](elems: NonEmptyChunk[(K, V)])(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = + apply(elems.head, elems.tail) + + /** + * Constructs a `NonEmptySortedMap` from a `NonEmptyList`. + */ + def fromNonEmptyList[K, V](elems: NonEmptyList[(K, V)])(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = + apply(elems.head, elems.tail) + + /** + * Constructs a `NonEmptySortedMap` from an element and `SortedMap`. + */ + def fromMap[K, V](elem: (K, V), others: SortedMap[K, V])(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = + apply(elem, others) + + /** + * Constructs a `NonEmptySortedMap` from a `SortedMap` or `None` otherwise. + */ + def fromMapOption[K, V](map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]): Option[NonEmptySortedMap[K, V]] + = map.headOption.map(fromMap(_, map.tail)) + + /** + * Constructs a `NonEmptySortedMap` from an `Iterable` or `None` otherwise. + */ + def fromIterableOption[K, V](iterable: Iterable[(K, V)])(implicit sOrdering: SOrdering[K]) + : Option[NonEmptySortedMap[K, V]] = + iterable.headOption.fold(None: Option[NonEmptySortedMap[K, V]])(h => Some(apply(h, iterable.tail))) + + /** + * Constructs a `NonEmptySortedMap` with the specified single value. + */ + def single[K, V](head: (K, V))(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = + NonEmptySortedMap(head) + + /** + * Provides an implicit conversion from `NonEmptySortedMap` to the `SortedMap` + * for interoperability with Scala's collection library. + */ + implicit def toMap[K, V](nonEmptyMap: NonEmptySortedMap[K, V]): SortedMap[K, V] = + nonEmptyMap.toMap + + private val NonEmptyMapSeed: Int = 1147820194 + +} + +trait NonEmptySortedMapSyntax { + implicit final class NonEmptySortedMapIterableOps[K, V](private val iterable: Iterable[(K, V)])( + implicit sOrdering: SOrdering[K]) { + + /** + * Constructs a `NonEmptySortedMap` from an `Iterable` or `None` otherwise. + */ + def toNonEmptyMap: Option[NonEmptySortedMap[K, V]] = + NonEmptySortedMap.fromIterableOption(iterable) + } + implicit final class NonEmptySortedMapMapOps[K, V](self: SortedMap[K, V])(implicit sOrdering: SOrdering[K]) { + + /** + * Constructs a `NonEmptySortedMap` from a `SortedMap` or `None` otherwise. + */ + def toNonEmptyMap: Option[NonEmptySortedMap[K, V]] = + NonEmptySortedMap.fromMapOption(self) + } +} diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala new file mode 100644 index 000000000..ee4e7c7b3 --- /dev/null +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala @@ -0,0 +1,264 @@ +/* + * Copyright 2020-2022 John A. De Goes and the ZIO Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package zio.prelude + +import scala.math.{Ordering => SOrdering} +import zio.NonEmptyChunk +import zio.prelude.coherent.HashPartialOrd + +import scala.collection.immutable.{SortedSet, TreeSet} +import scala.language.implicitConversions + +final class NonEmptySortedSet[A] private (private val set: SortedSet[A]) { self => + + /** Converts this `NonEmptySortedSet` to a `SortedSet`. */ + def toSet: SortedSet[A] = set + + /** + * Returns an element of this `NonEmptySortedSet` and the remainder, which is a (possibly empty) `SortedSet`. + */ + @inline + def peel: (A, SortedSet[A]) = (set.head, set.tail) + + /** + * Returns an element of this `NonEmptySortedSet` + * and the remainder or `None`, if the remainder is empty. + */ + def peelNonEmpty: (A, Option[NonEmptySortedSet[A]]) = { + val (head, tail) = peel + if (tail.isEmpty) + (head, None) + else + (head, Some(new NonEmptySortedSet(tail))) + } + + /** + * Converts this `NonEmptySortedSet` to a `NonEmptyChunk`. + */ + def toNonEmptyChunk: NonEmptyChunk[A] = peel match { case (head, tail) => NonEmptyChunk.fromIterable(head, tail) } + + /** + * Converts this `NonEmptySortedSet` to a `NonEmptyList`. + */ + def toNonEmptyList: NonEmptyList[A] = peel match { case (head, tail) => NonEmptyList.fromIterable(head, tail) } + + /** + * Creates a new `NonEmptySortedSet` with an additional element, unless the element is + * already present. + * + * @param elem the element to be added + * @return a new set that contains all elements of this set and that also + * contains `elem`. + */ + def +(elem: A): NonEmptySortedSet[A] = new NonEmptySortedSet(set + elem) + + /** + * Computes the union between of `NonEmptySortedSet` and another set. + * + * @param that the set to form the union with. + * @return a new `NonEmptySortedSet` consisting of all elements that are in this + * set or in the given set `that`. + */ + def union(that: SortedSet[A]): NonEmptySortedSet[A] = new NonEmptySortedSet(set.union(that)) + + /** + * Creates a new `NonEmptySortedSet` by adding all elements contained in another collection to this `NonEmptySortedSet`, omitting duplicates. + * + * This method takes a collection of elements and adds all elements, omitting duplicates, into `NonEmptySortedSet`. + * + * Example: + * {{{ + * scala> val a = NonEmptySortedSet(1, 2) ++ NonEmptySortedSet(2, "a") + * a: zio.prelude.NonEmptySortedSet[Any] = NonEmptySortedSet(1, 2, a) + * }}} + * + * @param elems the collection containing the elements to add. + * @return a new `NonEmptySortedSet` with the given elements added, omitting duplicates. + */ + def ++(elems: Iterable[A]): NonEmptySortedSet[A] = new NonEmptySortedSet(set ++ elems) + + /** Adds the `elem` to this `NonEmptySortedSet`. Alias for `+`. */ + def add(elem: A): NonEmptySortedSet[A] = self + elem + + /** Removes the `elem` from this `NonEmptySortedSet`. Alias for `-`. */ + def remove(elem: A): SortedSet[A] = set - elem + + /** + * removes the elem from `NonEmptySortedSet`, returning Some(NonEmptySortedSet) if there's anything + * left, otherwise None + */ + def removeNonEmpty(elem: A): Option[NonEmptySortedSet[A]] = { + val newSet = set - elem + if (newSet.nonEmpty) Some(new NonEmptySortedSet(set)) else None + } + + /** + * Returns the tail of this `NonEmptySortedSet` if it exists or `None` otherwise. + */ + def tailNonEmpty: Option[NonEmptySortedSet[A]] = peelNonEmpty._2 + + def map[B](f: A => B)(implicit sOrdering: SOrdering[B]): NonEmptySortedSet[B] = new NonEmptySortedSet(set.map(f)) + + override def hashCode: Int = set.hashCode ^ NonEmptySortedSet.NonEmptySortedSetSeed + + override def equals(that: Any): Boolean = + that match { + case that: AnyRef if self.eq(that) => true + case that: NonEmptySortedSet[_] => self.set == that.toSet + case _ => false + } + + override def toString: String = s"NonEmpty$set" +} + +object NonEmptySortedSet { + def apply[A](elem: A, others: Iterable[A])(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = { + val treeSet = new TreeSet() + elem ++ others + new NonEmptySortedSet(treeSet) + } + + def apply[A](elem: A, others:A*)(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = + apply(elem, others) + + def unapply[A](arg: NonEmptySortedSet[A]): Some[(A, SortedSet[A])] = Some(arg.peel) + + /** + * Constructs a `NonEmptyChunk` from a `NonEmptyList`. + */ + def fromNonEmptyChunk[A](elems: NonEmptyChunk[A])(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = + apply(elems.head, elems.tail) + + /** + * Constructs a `NonEmptySortedSet` from a `NonEmptyList`. + */ + def fromNonEmptyList[A](elems: NonEmptyList[A])(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = + apply(elems.head, elems.tail) + + /** + * Constructs a `NonEmptySortedSet` from an element and `SortedSet`. + */ + def fromSet[A](elem: A, others: SortedSet[A])(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = + apply(elem, others) + + /** + * Constructs a `NonEmptySortedSet` from a `SortedSet` or `None` otherwise. + */ + def fromSetOption[A](set: SortedSet[A])(implicit ordering: SOrdering[A]): Option[NonEmptySortedSet[A]] = + set.headOption.map(fromSet(_, set.tail)) + + /** + * Constructs a `NonEmptySortedSet` from an `Iterable` or `None` otherwise. + */ + def fromIterableOption[A](iterable: Iterable[A])(implicit ordering: SOrdering[A]): Option[NonEmptySortedSet[A]] = + iterable.headOption.fold(None: Option[NonEmptySortedSet[A]])(h => Some(apply(h, iterable.tail))) + + /** + * Constructs a `NonEmptySortedSet` with the specified single value. + */ + def single[A](head: A)(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = + apply(head) + + /** Creates a `NonEmptySortedSet` containing elements from `l` and `r` */ + def union[A](l: NonEmptySortedSet[A], r: SortedSet[A])(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = { + val (head, tail) = l.peel + NonEmptySortedSet.fromSet(head, tail.union(r)) + } + + /** Creates a `NonEmptySortedSet` containing elements from `l` and `r` */ + def union[A](l: SortedSet[A], r: NonEmptySortedSet[A])(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = + union(r, l) + + /** + * The `CommutativeEither` instance for `NonEmptySortedSet`. + * todo + implicit val NonEmptySortedSetCommutativeEither: CommutativeEither[NonEmptySortedSet] = + new CommutativeEither[NonEmptySortedSet] { + def either[A, B](fa: => NonEmptySortedSet[A], fb: => NonEmptySortedSet[B])( + implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[Either[A, B]] = + fa.map[Either[A, B]](Left(_)).union(fb.map[Either[A, B]](Right(_))) + } +*/ + /** + * The `Commutative` and `Idempotent` (and thus `Associative`) instance for `NonEmptySortedSet`. + */ + implicit def NonEmptySortedSetCommutativeIdempotent[A](implicit aOrd: SOrdering[A]): Commutative[NonEmptySortedSet[A]] with Idempotent[NonEmptySortedSet[A]] = + new Commutative[NonEmptySortedSet[A]] with Idempotent[NonEmptySortedSet[A]] { + override def combine(l: => NonEmptySortedSet[A], r: => NonEmptySortedSet[A]): NonEmptySortedSet[A] = + l union r.toSet + } + + /** + * Derives a `Debug[NonEmptySortedSet[A]]` given a `Debug[A]`. + */ + implicit def NonEmptySortedSetDebug[A: Debug]: Debug[NonEmptySortedSet[A]] = + chunk => Debug.Repr.VConstructor(List("zio", "prelude"), "NonEmptySortedSet", chunk.toNonEmptyList.map(_.debug).toCons) + + /** + * The `DeriveEqual` instance for `NonEmptySortedSet`. + */ + implicit val NonEmptySortedSetDeriveEqual: DeriveEqual[NonEmptySortedSet] = + new DeriveEqual[NonEmptySortedSet] { + def derive[A: Equal]: Equal[NonEmptySortedSet[A]] = + NonEmptySortedSetHashPartialOrd + } + + + /** + * Derives a `Hash[NonEmptySortedSet[A]]` and `PartialOrd[NonEmptySortedSet[A]]` (and thus `Equal[NonEmptyList[A]]`) instance. + */ + implicit def NonEmptySortedSetHashPartialOrd[A]: Hash[NonEmptySortedSet[A]] with PartialOrd[NonEmptySortedSet[A]] = + HashPartialOrd.derive[Set[A]].contramap(_.toSet) + + /** + * The `Invariant` instance for `NonEmptySortedSet`. + * todo - don't understand + implicit val NonEmptySortedSetInvariant: Invariant[NonEmptySortedSet] = + new Invariant[NonEmptySortedSet] { + def invmap[A, B](f: A <=> B)(implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[A] <=> NonEmptySortedSet[B] = + Equivalence[NonEmptySortedSet[A], NonEmptySortedSet[B]](a => a.map(f.to), b => b.map(f.from)) + } + */ + + /** + * Provides an implicit conversion from `NonEmptySortedSet` to the `Set` + * for interoperability with Scala's collection library. + */ + implicit def toSet[A](nonEmptySet: NonEmptySortedSet[A]): Set[A] = + nonEmptySet.toSet + + + private val NonEmptySortedSetSeed: Int = 1247120194 + +} + +trait NonEmptySortedSetSyntax { + implicit final class NonEmptySortedSetIterableOps[A](private val iterable: Iterable[A])(implicit aOrd: SOrdering[A]) { + + /** + * Constructs a `NonEmptySortedSet` from an `Iterable` or `None` otherwise. + */ + def toNonEmptySortedSet: Option[NonEmptySortedSet[A]] = NonEmptySortedSet.fromIterableOption(iterable) + } + implicit final class NonEmptySortedSetSetOps[A](self: SortedSet[A])(implicit aOrd: SOrdering[A]) { + + /** + * Constructs a `NonEmptySortedSet` from a `Set` or `None` otherwise. + */ + def toNonEmptySortedSet: Option[NonEmptySortedSet[A]] = NonEmptySortedSet.fromSetOption(self) + } +} + From 85047e6bb4357b539ce6600bcd9b9780176d4d2b Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 27 May 2022 12:02:01 +0100 Subject: [PATCH 2/4] modified my non-empty contributions to remove (hopefully) scala 2.13 dependency --- .../main/scala/zio/prelude/NonEmptyMap.scala | 31 +++++++------- .../scala/zio/prelude/NonEmptySortedMap.scala | 33 ++++++++------- .../scala/zio/prelude/NonEmptySortedSet.scala | 42 +++++++++---------- 3 files changed, 52 insertions(+), 54 deletions(-) diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala b/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala index b940da752..583c70c04 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala @@ -16,7 +16,6 @@ package zio.prelude * limitations under the License. */ - import zio.NonEmptyChunk import scala.language.implicitConversions @@ -25,9 +24,9 @@ import scala.language.implicitConversions * A non-empty wrapper for the scala immutable map. Note - this does not attempt to implement all features of * map but what the author considers to be the "normal ones". */ -case class NonEmptyMap[K, V] private(private val map: Map[K, V]) { self => +case class NonEmptyMap[K, V] private (private val map: Map[K, V]) { self => - private def newMap[V2](map: Map[K, V2]): NonEmptyMap[K,V2] = new NonEmptyMap(map) + private def newMap[V2](map: Map[K, V2]): NonEmptyMap[K, V2] = new NonEmptyMap(map) /** Converts this `NonEmptyMap` to a `Map`. */ def toMap: Map[K, V] = map @@ -50,7 +49,6 @@ case class NonEmptyMap[K, V] private(private val map: Map[K, V]) { self => (head, Some(newMap(tail))) } - /** * Creates a new `NonEmptyMap` with an additional element, unless the element is * already present. @@ -59,7 +57,7 @@ case class NonEmptyMap[K, V] private(private val map: Map[K, V]) { self => * @return a new map that contains all elements of this map and that also * contains `elem`. */ - def +(elem: (K,V)): NonEmptyMap[K, V] = newMap(map + elem) + def +(elem: (K, V)): NonEmptyMap[K, V] = newMap(map + elem) /** * Creates a new `NonEmptyMap` by adding all elements contained in another collection to this `NonEmptyMap`, omitting duplicates. @@ -102,7 +100,7 @@ case class NonEmptyMap[K, V] private(private val map: Map[K, V]) { self => override def equals(that: Any): Boolean = that match { case that: AnyRef if self.eq(that) => true - case that: NonEmptyMap[_, _] => self.map == that.toMap + case that: NonEmptyMap[_, _] => self.map == that.toMap case _ => false } @@ -176,33 +174,33 @@ object NonEmptyMap { * GroupByOption function returns an option of a nonEmpty map instead of a map because by definition * the elements will be non-empty - returns None if from is */ - def groupByOption[A, K](from: Iterable[A])(f: A => K): Option[NonEmptyMap[K, Iterable[A]]] = + def groupByOption[A, K](from: Iterable[A])(f: A => K): Option[NonEmptyMap[K, Iterable[A]]] = from.headOption.map(_ => NonEmptyMap(from.groupBy(f))) /** * from a non-empty chunk we can create a non-empty map of non-empty chunks */ - def groupByFromNonEmptyChunk[A, K](from: NonEmptyChunk[A])(f: A => K): NonEmptyMap[K, NonEmptyChunk[A]] = { - val gb = from.groupBy(f) - val asChunks =gb.map{ p => (p._1 -> NonEmptyChunk.fromIterableOption(p._2).get) } // safe! + def groupByFromNonEmptyChunk[A, K](from: NonEmptyChunk[A])(f: A => K): NonEmptyMap[K, NonEmptyChunk[A]] = { + val gb = from.groupBy(f) + val asChunks = gb.map(p => (p._1 -> NonEmptyChunk.fromIterableOption(p._2).get)) // safe! NonEmptyMap(asChunks) } /** * from a non-empty set we can create a non-empty map of non-empty sets */ - def groupByFromNonEmptySet[A, K](from: NonEmptySet[A])(f: A => K): NonEmptyMap[K, NonEmptySet[A]] = { - val gb = from.groupBy(f) - val asSets = gb.map { p => (p._1 -> NonEmptySet.fromIterableOption(p._2).get) } // safe! + def groupByFromNonEmptySet[A, K](from: NonEmptySet[A])(f: A => K): NonEmptyMap[K, NonEmptySet[A]] = { + val gb = from.groupBy(f) + val asSets = gb.map(p => (p._1 -> NonEmptySet.fromIterableOption(p._2).get)) // safe! NonEmptyMap(asSets) } /** * from a non-empty list we can create a non-empty map of non-empty list */ - def groupByFromNonEmptyList[A, K](from: NonEmptyList[A])(f: A => K): NonEmptyMap[K, NonEmptyList[A]] = { - val gb = from.groupBy(f) - val asLists = gb.map { p => (p._1 -> NonEmptyList.fromIterableOption(p._2).get) } // safe! + def groupByFromNonEmptyList[A, K](from: NonEmptyList[A])(f: A => K): NonEmptyMap[K, NonEmptyList[A]] = { + val gb = from.groupBy(f) + val asLists = gb.map(p => (p._1 -> NonEmptyList.fromIterableOption(p._2).get)) // safe! NonEmptyMap(asLists) } @@ -224,4 +222,3 @@ trait NonEmptyMapSyntax { def toNonEmptyMap: Option[NonEmptyMap[K, V]] = NonEmptyMap.fromMapOption(self) } } - diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala index 8703ad302..bf4a4e983 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala @@ -16,7 +16,6 @@ package zio.prelude * limitations under the License. */ - import zio.NonEmptyChunk import scala.collection.immutable.SortedMap @@ -27,9 +26,10 @@ import scala.math.{Ordering => SOrdering} * A non-empty wrapper for the scala immutable map. Note - this does not attempt to implement all features of * map but what the author considers to be the "normal ones". */ -case class NonEmptySortedMap[K, V] private(private val map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]) { self => +case class NonEmptySortedMap[K, V] private (private val map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]) { + self => - private def newMap[V2](map: SortedMap[K, V2]): NonEmptySortedMap[K,V2] = new NonEmptySortedMap(map) + private def newMap[V2](map: SortedMap[K, V2]): NonEmptySortedMap[K, V2] = new NonEmptySortedMap(map) /** Converts this `NonEmptySortedMap` to a `SortedMap`. */ def toMap: SortedMap[K, V] = map @@ -52,7 +52,6 @@ case class NonEmptySortedMap[K, V] private(private val map: SortedMap[K, V])(imp (head, Some(newMap(tail))) } - /** * Creates a new `NonEmptySortedMap` with an additional element, unless the element is * already present. @@ -61,7 +60,7 @@ case class NonEmptySortedMap[K, V] private(private val map: SortedMap[K, V])(imp * @return a new map that contains all elements of this map and that also * contains `elem`. */ - def +(elem: (K,V)): NonEmptySortedMap[K, V] = newMap(map + elem) + def +(elem: (K, V)): NonEmptySortedMap[K, V] = newMap(map + elem) /** * Creates a new `NonEmptySortedMap` by adding all elements contained in another collection to this `NonEmptySortedMap`, omitting duplicates. @@ -91,10 +90,10 @@ case class NonEmptySortedMap[K, V] private(private val map: SortedMap[K, V])(imp def tailNonEmpty: Option[NonEmptySortedMap[K, V]] = peelNonEmpty._2 /** - * Produces a new non empty map where values mapped according to function f. + * Produces a new non empty map where values mapped according to function f. */ - def mapValues[V1](f: V => V1) = { - val newInner = map.map{ p => (p._1, f(p._2))} + def mapValues[V1](f: V => V1): NonEmptySortedMap[K, V1] = { + val newInner = map.map(p => (p._1, f(p._2))) newMap(newInner) } @@ -103,7 +102,7 @@ case class NonEmptySortedMap[K, V] private(private val map: SortedMap[K, V])(imp override def equals(that: Any): Boolean = that match { case that: AnyRef if self.eq(that) => true - case that: NonEmptySortedMap[_, _] => self.map == that.toMap + case that: NonEmptySortedMap[_, _] => self.map == that.toMap case _ => false } @@ -113,7 +112,7 @@ case class NonEmptySortedMap[K, V] private(private val map: SortedMap[K, V])(imp object NonEmptySortedMap { def apply[K, V](elem: (K, V), others: Iterable[(K, V)])(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = - new NonEmptySortedMap(SortedMap.from(others.toMap) + elem) + new NonEmptySortedMap(SortedMap(others.toList:_*) + elem) /** * Creates a `NonEmptySortedMap` with the specified elements. @@ -148,14 +147,15 @@ object NonEmptySortedMap { /** * Constructs a `NonEmptySortedMap` from a `SortedMap` or `None` otherwise. */ - def fromMapOption[K, V](map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]): Option[NonEmptySortedMap[K, V]] - = map.headOption.map(fromMap(_, map.tail)) + def fromMapOption[K, V](map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]): Option[NonEmptySortedMap[K, V]] = + map.headOption.map(fromMap(_, map.tail)) /** * Constructs a `NonEmptySortedMap` from an `Iterable` or `None` otherwise. */ - def fromIterableOption[K, V](iterable: Iterable[(K, V)])(implicit sOrdering: SOrdering[K]) - : Option[NonEmptySortedMap[K, V]] = + def fromIterableOption[K, V](iterable: Iterable[(K, V)])(implicit + sOrdering: SOrdering[K] + ): Option[NonEmptySortedMap[K, V]] = iterable.headOption.fold(None: Option[NonEmptySortedMap[K, V]])(h => Some(apply(h, iterable.tail))) /** @@ -176,8 +176,9 @@ object NonEmptySortedMap { } trait NonEmptySortedMapSyntax { - implicit final class NonEmptySortedMapIterableOps[K, V](private val iterable: Iterable[(K, V)])( - implicit sOrdering: SOrdering[K]) { + implicit final class NonEmptySortedMapIterableOps[K, V](private val iterable: Iterable[(K, V)])(implicit + sOrdering: SOrdering[K] + ) { /** * Constructs a `NonEmptySortedMap` from an `Iterable` or `None` otherwise. diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala index ee4e7c7b3..7afe0c961 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala @@ -118,7 +118,7 @@ final class NonEmptySortedSet[A] private (private val set: SortedSet[A]) { self override def equals(that: Any): Boolean = that match { case that: AnyRef if self.eq(that) => true - case that: NonEmptySortedSet[_] => self.set == that.toSet + case that: NonEmptySortedSet[_] => self.set == that.toSet case _ => false } @@ -131,7 +131,7 @@ object NonEmptySortedSet { new NonEmptySortedSet(treeSet) } - def apply[A](elem: A, others:A*)(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = + def apply[A](elem: A, others: A*)(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = apply(elem, others) def unapply[A](arg: NonEmptySortedSet[A]): Some[(A, SortedSet[A])] = Some(arg.peel) @@ -185,17 +185,19 @@ object NonEmptySortedSet { /** * The `CommutativeEither` instance for `NonEmptySortedSet`. * todo - implicit val NonEmptySortedSetCommutativeEither: CommutativeEither[NonEmptySortedSet] = - new CommutativeEither[NonEmptySortedSet] { - def either[A, B](fa: => NonEmptySortedSet[A], fb: => NonEmptySortedSet[B])( - implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[Either[A, B]] = - fa.map[Either[A, B]](Left(_)).union(fb.map[Either[A, B]](Right(_))) - } -*/ + * implicit val NonEmptySortedSetCommutativeEither: CommutativeEither[NonEmptySortedSet] = + * new CommutativeEither[NonEmptySortedSet] { + * def either[A, B](fa: => NonEmptySortedSet[A], fb: => NonEmptySortedSet[B])( + * implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[Either[A, B]] = + * fa.map[Either[A, B]](Left(_)).union(fb.map[Either[A, B]](Right(_))) + * } + */ /** * The `Commutative` and `Idempotent` (and thus `Associative`) instance for `NonEmptySortedSet`. */ - implicit def NonEmptySortedSetCommutativeIdempotent[A](implicit aOrd: SOrdering[A]): Commutative[NonEmptySortedSet[A]] with Idempotent[NonEmptySortedSet[A]] = + implicit def NonEmptySortedSetCommutativeIdempotent[A](implicit + aOrd: SOrdering[A] + ): Commutative[NonEmptySortedSet[A]] with Idempotent[NonEmptySortedSet[A]] = new Commutative[NonEmptySortedSet[A]] with Idempotent[NonEmptySortedSet[A]] { override def combine(l: => NonEmptySortedSet[A], r: => NonEmptySortedSet[A]): NonEmptySortedSet[A] = l union r.toSet @@ -205,7 +207,8 @@ object NonEmptySortedSet { * Derives a `Debug[NonEmptySortedSet[A]]` given a `Debug[A]`. */ implicit def NonEmptySortedSetDebug[A: Debug]: Debug[NonEmptySortedSet[A]] = - chunk => Debug.Repr.VConstructor(List("zio", "prelude"), "NonEmptySortedSet", chunk.toNonEmptyList.map(_.debug).toCons) + chunk => + Debug.Repr.VConstructor(List("zio", "prelude"), "NonEmptySortedSet", chunk.toNonEmptyList.map(_.debug).toCons) /** * The `DeriveEqual` instance for `NonEmptySortedSet`. @@ -216,7 +219,6 @@ object NonEmptySortedSet { NonEmptySortedSetHashPartialOrd } - /** * Derives a `Hash[NonEmptySortedSet[A]]` and `PartialOrd[NonEmptySortedSet[A]]` (and thus `Equal[NonEmptyList[A]]`) instance. */ @@ -226,12 +228,12 @@ object NonEmptySortedSet { /** * The `Invariant` instance for `NonEmptySortedSet`. * todo - don't understand - implicit val NonEmptySortedSetInvariant: Invariant[NonEmptySortedSet] = - new Invariant[NonEmptySortedSet] { - def invmap[A, B](f: A <=> B)(implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[A] <=> NonEmptySortedSet[B] = - Equivalence[NonEmptySortedSet[A], NonEmptySortedSet[B]](a => a.map(f.to), b => b.map(f.from)) - } - */ + * implicit val NonEmptySortedSetInvariant: Invariant[NonEmptySortedSet] = + * new Invariant[NonEmptySortedSet] { + * def invmap[A, B](f: A <=> B)(implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[A] <=> NonEmptySortedSet[B] = + * Equivalence[NonEmptySortedSet[A], NonEmptySortedSet[B]](a => a.map(f.to), b => b.map(f.from)) + * } + */ /** * Provides an implicit conversion from `NonEmptySortedSet` to the `Set` @@ -240,9 +242,8 @@ object NonEmptySortedSet { implicit def toSet[A](nonEmptySet: NonEmptySortedSet[A]): Set[A] = nonEmptySet.toSet - private val NonEmptySortedSetSeed: Int = 1247120194 - + } trait NonEmptySortedSetSyntax { @@ -261,4 +262,3 @@ trait NonEmptySortedSetSyntax { def toNonEmptySortedSet: Option[NonEmptySortedSet[A]] = NonEmptySortedSet.fromSetOption(self) } } - From 305e4f22a798523bb2fe7132db531eb1210064a0 Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 27 May 2022 13:23:14 +0100 Subject: [PATCH 3/4] deleted some comments, changed to final class --- .../main/scala/zio/prelude/NonEmptyMap.scala | 10 +++++----- .../scala/zio/prelude/NonEmptySortedMap.scala | 4 ++-- .../scala/zio/prelude/NonEmptySortedSet.scala | 20 ------------------- 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala b/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala index 583c70c04..f18f32681 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptyMap.scala @@ -24,7 +24,7 @@ import scala.language.implicitConversions * A non-empty wrapper for the scala immutable map. Note - this does not attempt to implement all features of * map but what the author considers to be the "normal ones". */ -case class NonEmptyMap[K, V] private (private val map: Map[K, V]) { self => +final class NonEmptyMap[K, V] private (private val map: Map[K, V]) { self => private def newMap[V2](map: Map[K, V2]): NonEmptyMap[K, V2] = new NonEmptyMap(map) @@ -175,7 +175,7 @@ object NonEmptyMap { * the elements will be non-empty - returns None if from is */ def groupByOption[A, K](from: Iterable[A])(f: A => K): Option[NonEmptyMap[K, Iterable[A]]] = - from.headOption.map(_ => NonEmptyMap(from.groupBy(f))) + from.headOption.map(_ => new NonEmptyMap(from.groupBy(f))) /** * from a non-empty chunk we can create a non-empty map of non-empty chunks @@ -183,7 +183,7 @@ object NonEmptyMap { def groupByFromNonEmptyChunk[A, K](from: NonEmptyChunk[A])(f: A => K): NonEmptyMap[K, NonEmptyChunk[A]] = { val gb = from.groupBy(f) val asChunks = gb.map(p => (p._1 -> NonEmptyChunk.fromIterableOption(p._2).get)) // safe! - NonEmptyMap(asChunks) + new NonEmptyMap(asChunks) } /** @@ -192,7 +192,7 @@ object NonEmptyMap { def groupByFromNonEmptySet[A, K](from: NonEmptySet[A])(f: A => K): NonEmptyMap[K, NonEmptySet[A]] = { val gb = from.groupBy(f) val asSets = gb.map(p => (p._1 -> NonEmptySet.fromIterableOption(p._2).get)) // safe! - NonEmptyMap(asSets) + new NonEmptyMap(asSets) } /** @@ -201,7 +201,7 @@ object NonEmptyMap { def groupByFromNonEmptyList[A, K](from: NonEmptyList[A])(f: A => K): NonEmptyMap[K, NonEmptyList[A]] = { val gb = from.groupBy(f) val asLists = gb.map(p => (p._1 -> NonEmptyList.fromIterableOption(p._2).get)) // safe! - NonEmptyMap(asLists) + new NonEmptyMap(asLists) } } diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala index bf4a4e983..487570a2e 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySortedMap.scala @@ -26,7 +26,7 @@ import scala.math.{Ordering => SOrdering} * A non-empty wrapper for the scala immutable map. Note - this does not attempt to implement all features of * map but what the author considers to be the "normal ones". */ -case class NonEmptySortedMap[K, V] private (private val map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]) { +final class NonEmptySortedMap[K, V] private (private val map: SortedMap[K, V])(implicit sOrdering: SOrdering[K]) { self => private def newMap[V2](map: SortedMap[K, V2]): NonEmptySortedMap[K, V2] = new NonEmptySortedMap(map) @@ -112,7 +112,7 @@ case class NonEmptySortedMap[K, V] private (private val map: SortedMap[K, V])(im object NonEmptySortedMap { def apply[K, V](elem: (K, V), others: Iterable[(K, V)])(implicit sOrdering: SOrdering[K]): NonEmptySortedMap[K, V] = - new NonEmptySortedMap(SortedMap(others.toList:_*) + elem) + new NonEmptySortedMap(SortedMap(others.toList: _*) + elem) /** * Creates a `NonEmptySortedMap` with the specified elements. diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala index 7afe0c961..a1c8bd662 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala @@ -182,16 +182,6 @@ object NonEmptySortedSet { def union[A](l: SortedSet[A], r: NonEmptySortedSet[A])(implicit ordering: SOrdering[A]): NonEmptySortedSet[A] = union(r, l) - /** - * The `CommutativeEither` instance for `NonEmptySortedSet`. - * todo - * implicit val NonEmptySortedSetCommutativeEither: CommutativeEither[NonEmptySortedSet] = - * new CommutativeEither[NonEmptySortedSet] { - * def either[A, B](fa: => NonEmptySortedSet[A], fb: => NonEmptySortedSet[B])( - * implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[Either[A, B]] = - * fa.map[Either[A, B]](Left(_)).union(fb.map[Either[A, B]](Right(_))) - * } - */ /** * The `Commutative` and `Idempotent` (and thus `Associative`) instance for `NonEmptySortedSet`. */ @@ -225,16 +215,6 @@ object NonEmptySortedSet { implicit def NonEmptySortedSetHashPartialOrd[A]: Hash[NonEmptySortedSet[A]] with PartialOrd[NonEmptySortedSet[A]] = HashPartialOrd.derive[Set[A]].contramap(_.toSet) - /** - * The `Invariant` instance for `NonEmptySortedSet`. - * todo - don't understand - * implicit val NonEmptySortedSetInvariant: Invariant[NonEmptySortedSet] = - * new Invariant[NonEmptySortedSet] { - * def invmap[A, B](f: A <=> B)(implicit aOrd: SOrdering[A], bOrd: SOrdering[B]): NonEmptySortedSet[A] <=> NonEmptySortedSet[B] = - * Equivalence[NonEmptySortedSet[A], NonEmptySortedSet[B]](a => a.map(f.to), b => b.map(f.from)) - * } - */ - /** * Provides an implicit conversion from `NonEmptySortedSet` to the `Set` * for interoperability with Scala's collection library. From 42531dd5b2a55c8c91fe544848b220bfbc2e57f6 Mon Sep 17 00:00:00 2001 From: tim Date: Fri, 27 May 2022 14:51:07 +0100 Subject: [PATCH 4/4] ran fix --- core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala index a1c8bd662..76fb70f25 100644 --- a/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala +++ b/core/shared/src/main/scala/zio/prelude/NonEmptySortedSet.scala @@ -16,12 +16,12 @@ package zio.prelude -import scala.math.{Ordering => SOrdering} import zio.NonEmptyChunk import zio.prelude.coherent.HashPartialOrd import scala.collection.immutable.{SortedSet, TreeSet} import scala.language.implicitConversions +import scala.math.{Ordering => SOrdering} final class NonEmptySortedSet[A] private (private val set: SortedSet[A]) { self =>