Here's an ADT which is not a GADT, in Haskell:
data Expr = IntExpr Int | BoolExpr Bool
import cats.Traverse | |
import cats.effect._ | |
import cats.effect.concurrent.Semaphore | |
import cats.temp.par._ | |
import cats.syntax.all._ | |
import scala.concurrent.duration._ | |
object Main extends IOApp { | |
import ParTask._ |
import cats.data.Kleisli | |
import cats.effect.{ Concurrent, Sync } | |
import cats.effect.concurrent.MVar | |
import cats.implicits._ | |
import cats.{ Applicative, Functor, Monad } | |
// Let's start with our dsl | |
// First we need to interact with a console | |
trait Console[F[_]] { |
package quantified | |
import cats.Monad | |
import scala.language.implicitConversions | |
/** C[_] constraint applied to type F[_, _] quantified in first parameter */ | |
final class Quant[+C[_[_]], F[_, _]] private (private val erased: C[F[Any, ?]]) extends AnyVal { | |
type State = Defined |
import cats.effect._ | |
import cats.syntax.functor._ | |
import fs2._ | |
import java.nio.file.Paths | |
import java.util.concurrent.Executors | |
import scala.concurrent.ExecutionContext | |
import scala.util.Try | |
object CsvApp extends IOApp { |
import cats.Id | |
import polymorphic._ | |
import polymorphic.syntax.all._ | |
// Type mismatch: found b.type, required: A | |
//def nope[A, B](f: A => List[A], b: B, s: String): (List[B], List[String]) = (f(b), f(s)) | |
// If Scala had Rank-N types it would be defined as: | |
//def notValid[B](f: (A => List[A]) forAll { A }, b: B, s: String): (List[B], List[String]) = (f(b), f(s)) |
import polymorphic._ | |
import polymorphic.syntax.all._ | |
class Data[A](val x: A, val f: A => String) | |
trait E { | |
def f(ex: ∃[Data]): String = ex match { case Exists(d) => d.f(d.x) } | |
} | |
val e = new E {} |
// This is the traditional encoding, using abstract type members | |
// to encode existentials | |
object AbstractExistentials { | |
trait E { | |
type X | |
val x: X | |
def f(p: X): String | |
} | |