functional programming - Erroneous Scala code using polymorphic ADT type checks -


i'm doing exercises better understand io monads (following functional programming in scala), , managed write erroneous code somehow passed compilation , caused me headache.

in below example, writing stack-safe interpreter of io monad. code in pattern matching on polymorphic algebraic data type (flatmap[a, b]). error in code k1 andthen k2; 2 functions can't compose because k1 returning different type (io[b]) k2 expects (b). the code still type-checks somehow, , typechecking error because, in runtime, there classcastexception @ automatic unboxing (just if using unsafe cast in java). there no compiler warnings issued.

the code (also found on gist):

  object iomonadexercise extends app {    sealed trait io[a]       case class return[a](value: a) extends io[a]       case class suspend[a](f: () => a) extends io[a]       case class flatmap[a, b](io: io[a], cont: => io[b]) extends io[b]    object io {     def apply[a](a: => a): io[a] = suspend(() => a)   }    object interpreter {     def run[a](io: io[a]): = {       io match {         case return(a) =>         case suspend(f) => f()          case flatmap(return(a), cont) => run(cont(a))         case flatmap(suspend(f), cont) => run(cont(f()))          // case compiles whatever reason shouldn't type check (k1 returns io[b] , k2 expects b)         // accordingly, there classcastexception in runtime         case flatmap(flatmap(io1, k1), k2) => run(flatmap(io1, k1 andthen k2))          // case 1 works //        case flatmap(flatmap(io1, k1), k2) => run(flatten(io1, k1, k2))       }     }      def flatten[a, b, c](io: io[a], k1: => io[b], k2: b => io[c]): flatmap[a, c] = {       flatmap(io, => flatmap(k1(a), k2))     }   }     def sum(i: int): io[int] = {     stream.range(0, i).foldleft(io(0))((io, i) => flatmap(io, (s: int) => io(s + i)))   }    val n = 100000   val sumnio: io[int] = sum(n)   val sumn: int = interpreter.run(sumnio)   println(s"sum of 1..$n io loop  : $sumn")   println(s"sum of 1..$n math expr: ${n * (n - 1) / 2}")   assert(sumn == n * (n - 1) / 2) } 

what going on? compiler bug? or known limitation of type inference? or there explanation this?

i've tested on both scala 2.11.8 , on 2.12.0, , behavior seems same: code compiles without warnings.

i think case of si-5195 bug. if construct nested flatmap manually, cannot write andthen, because types known , k1 , k2 not composable.

but in pattern matching types of io1, k1 , k2 not known in advance, have inferred , see inferred wrong. [...]

edit here try explain how type-checks: if start inferring types k1 , k2 yourself, come with

  • k1: x => io[y] , k2: y => io[a] x , y
  • plus k1 andthen k2 need io[y] <: y

so there exist type y satisfies these restrictions? yes, it's any. when apply it, io[y] becomes suspend[int] , y int subtype relation doesn't hold.


Comments

Popular posts from this blog

sql server - Cannot query correctly (MSSQL - PHP - JSON) -

php - trouble displaying mysqli database results in correct order -

C++ Linked List -