-
-
Save rossabaker/2f50e77cecc6afd096dd7895f763b5f6 to your computer and use it in GitHub Desktop.
scala> import org.typelevel.ci._ | |
import org.typelevel.ci._ | |
scala> val f: String => CIString = CIString.apply | |
val f: String => org.typelevel.ci.CIString = $Lambda$1025/2055291664@4bbf38b8 | |
scala> val g: CIString => String = _.toString | |
val g: org.typelevel.ci.CIString => String = $Lambda$1027/1152113439@62108cd3 | |
scala> val rosses = Set("Ross", "ROSS", "ross") // three too many if you ask me | |
val rosses: scala.collection.immutable.Set[String] = Set(Ross, ROSS, ross) | |
scala> rosses.map(f).map(g) | |
val res0: scala.collection.immutable.Set[String] = Set(Ross) | |
scala> rosses.map(f andThen g) | |
val res1: scala.collection.immutable.Set[String] = Set(Ross, ROSS, ross) |
That f
is enough to collapse the set, but you also need a g
that breaks substitution to fail the property:
scala> val set = Set("a1", "a2", "a3")
val set: Set[String] = Set(a1, a2, a3)
scala> val f: String => String = _.take(1)
val f: String => String = Lambda$1356/1810172725@304744a1
scala> val g: String => Int = System.identityHashCode _
val g: String => Int = Lambda$1362/2029374405@70697478
scala> set.map(f).map(g)
val res0: Set[Int] = Set(1512070885)
scala> set.map(f andThen g)
val res1: Set[Int] = Set(1151421920, 1358787485, 1578964260)
@rossabaker yes - Nice example there, thank you 👍
On second thought, that was a bad example. The laws are only good for pure functions. System.identityHashCode
even breaks Functor[List]
:
scala> val list = List("a1", "a2", "a3")
val list: List[String] = List(a1, a2, a3)
scala> val f: String => String = _.take(1)
val f: String => String = Lambda$1362/563031889@16f34376
scala> val g: String => Int = System.identityHashCode _
val g: String => Int = Lambda$1369/1827344889@4d664323
scala> list.map(f).map(g)
val res0: List[Int] = List(1579775434, 953107607, 2068191651)
scala> list.map(f andThen g)
val res1: List[Int] = List(1206577437, 12691277, 1193744863)
I can't think of a function on String
that is pure but breaks substitution of equality.
@rossabaker believe it or not, I am kind of relieved, because when I saw your case-insensitive string example, part of me asked, what sort of function is this? Is it pure? Does it rely on some side effects or some state to produce its value? I didn't pursue the question sufficiently though. And when I briefly tried to come up with a function g that could complement the f function that turns "a1", "a2", etc into "a", when I noticed that I wasn't coming up with a candidate, I also asked myself if such a function would have to resort to some kind of 'trick' to behave in the desired way.
Well, thank you very much for letting me know.
The quest for compelling examples of how a Set is not a functor continues!
I don't know about "tricky". CIString
satisfies the contract of .equals
. There's no substitution law. cats.Eq
doesn't have one either. Haskell's Eq
recently added it as an "expectation", but officially has no laws. We should strongly prefer that property, but it's neither illegal nor unusual to break it. A couple more examples:
(s: Set[A] => s.toList)
(ordering is undefined)(d: Double) => 1.0 / d
(try it with0.0
and-0.0
)
A set whose equivalence relation guarantees substitution is a functor, but Scala's Set
doesn't, so it's not.
Noted. Thank you.
Hello,
Nice Example (digs up Functor Laws)
- from functor laws
I like it - I have not been able to come up with an example using the f function that they show in the following lecture, which maps all of a1, a2, a3 to a: https://t.co/ceM5HElr2J