New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Try.map violates functor composition law #6284
Comments
Imported From: https://issues.scala-lang.org/browse/SI-6284?orig=1 |
@jsuereth said: |
Dan Rosen (mergeconflict) said: In the case of
|
@odersky said: |
Dan Rosen (mergeconflict) said: |
Peter Pnin (pnin) said: Success(1) map { numberOrDefault compose divideByZero } |
Andrii Polishchuk (rgtbctltpx) said (edited on Oct 11, 2014 10:57:05 PM UTC): import scala.util._
object Main extends App {
def divideByZero(a: Int): Int = a / 0
def numberOrDefault(a: Int): Int =
try a catch { case _: ArithmeticException => 42 }
println(Success(1) map { numberOrDefault _ compose divideByZero _ })
println(Success(1) map divideByZero _ map numberOrDefault _)
} import scala.util._
object Main extends App {
def divideByZero(a: Int): Int = a / 0
def numberOrDefault(a: => Int): Int =
try a catch { case _: ArithmeticException => 42 }
println(Success(1) map { ((x: Int) => numberOrDefault(x)) compose divideByZero _ })
println(Success(1) map divideByZero _ map ((x: Int) => numberOrDefault(x)))
} You may argue this is the right example: http://ideone.com/TgkLCO import scala.util._
object Main extends App {
def divideByZero(a: Int): Int = a / 0
def numberOrDefault(a: => Int): Int =
try a catch { case _: ArithmeticException => 42 }
println(Success(1) map { x => numberOrDefault(divideByZero(x)) })
println(Success(1) map divideByZero _ map ((x: Int) => numberOrDefault(x)))
} But that's not true, because for "map (f . g)" case you use f = numberOrDefault
g = divideByZero and for "map g . map f" case you use another f: f = ((x: Int) => numberOrDefault(x))
g = divideByZero By this example you actually prove that numberOrDefault !== ((x: Int) => numberOrDefault( x )), which is quite obvious fact. |
@jsuereth said: If you ignore Bottom type, or otherwise throwing an exception as a possibility in functions, then the laws hold. See: http://www.haskell.org/haskellwiki/Hask "Platonic Hask". Again, claiming category theory laws really needs a category definition first, otherwise all of this postulation is meaningless. |
Jason Hu (HuStmpHrrr) said (edited on Oct 21, 2016 7:23:02 PM UTC): first of all, the so-called composition you are making is bogus. tryy map { p => g(() => f(p)) } doesn't have any assumption of relation to tryy map f map g but rather should be equivalent to tryy map { p => () => f(p) } map g don't let syntax trick you. also, another problem is Try is not a valid point of discussion anyways. Try handles side effects and expects ones. it's ok to not have this class escape from the laws. |
For all functions
f
andg
,Success(a) map { f compose g }
should produce the same result as
Success(a) map g map f
However, in the following example:
the property we want is not satisfied:
In order to satisfy the functor composition law in the above case, we need something like the following implementation for
Failure.map
:def map[U](f: T => U): Try[U] = Try[U](f(throw exception))
This allows the possibility of going from a
Failure
to aSuccess
, which is correct ifTry
is attempting to mimic the semantics of exception handling.EDIT: The same can be said for
Failure.flatMap
, by the way. It should also be possible for the function passed toflatMap
to catch the contained exception and produce aSuccess
, as above.The text was updated successfully, but these errors were encountered: