Last active
February 25, 2017 13:06
-
-
Save p-pavel/36cfe1c772bc3cd454a96545f781a313 to your computer and use it in GitHub Desktop.
Solving tagged types problem with elimination
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** Для решения проблемы с тем, что pattern matching в Scala теряет path dependent types | |
* | |
* @see [[https://gist.github.com/p-pavel/24e63bb9f40ea95fd988787a35ad4d80 this gist]] | |
* можно воспользоваться классикой -- introduce/eliminate | |
*/ | |
object Elimination { | |
import language.higherKinds | |
/** | |
* Элиминатор типа моделики | |
* @tparam F | |
*/ | |
trait ModelicaTypeEliminator[F[_]] { | |
final type C[A] = F[A] | |
def forReal : F[Double ] | |
def forBoolean : F[Boolean] | |
def forString : F[String ] | |
def forInteger : F[Int ] | |
} | |
/** | |
* Представление типа Modelica | |
*/ | |
trait ModelicaType { | |
type Native | |
def apply[F[_]](eliminator : ModelicaTypeEliminator[F]) : F[Native] | |
} | |
/** Реализация нативных типов в виде моделиковских */ | |
trait ModelicaTag[T] { | |
final type Native = T | |
} | |
@implicitNotFound(msg = "Cannot prove that ${T} can be represented as Modelica type") | |
trait PModelicaType[T] extends ModelicaType with ModelicaTag[T] | |
implicit object ModelicaInteger extends PModelicaType[Int] { | |
override def apply[F[_]](eliminator: ModelicaTypeEliminator[F]): F[Native] = eliminator.forInteger | |
} | |
implicit object ModelicaReal extends PModelicaType[Double] { | |
override def apply[F[_]](eliminator: ModelicaTypeEliminator[F]): F[Native] = eliminator.forReal | |
} | |
implicit object ModelicaBoolean extends PModelicaType[Boolean] { | |
override def apply[F[_]](eliminator: ModelicaTypeEliminator[F]): F[Native] = eliminator.forBoolean | |
} | |
implicit object ModelicaString extends PModelicaType[String] { | |
override def apply[F[_]](eliminator: ModelicaTypeEliminator[F]): F[Native] = eliminator.forString | |
} | |
/** Специальный элиминатор, где действия одинаковые (с точностью до полиморфизма) | |
* для любых типов | |
* @tparam F | |
*/ | |
trait Neutral[F[_]] extends ModelicaTypeEliminator[F] { | |
protected def neutral[A]() : F[A] | |
final override def forReal : F[Double ] = neutral() | |
final override def forBoolean : F[Boolean] = neutral() | |
final override def forString : F[String ] = neutral() | |
final override def forInteger : F[Int ] = neutral() | |
} | |
/** Пример -- создание хранилки по типу | |
* | |
* @tparam T | |
*/ | |
class ValueHolder[T] { | |
private var _lastValue : Option[T] = None | |
def lastValue : Option[T] = _lastValue | |
def lastValue_=(v : T) : Unit = _lastValue = Some(v) | |
} | |
object holderCreator extends Neutral[ValueHolder] { | |
override protected def neutral[A]() = new ValueHolder | |
} | |
import java.nio.ByteBuffer | |
/** Пример -- создание вычитывалки из [[java.nio.ByteBuffer]] | |
* по типу | |
*/ | |
object readerCreator extends ModelicaTypeEliminator[({type F[A] = ByteBuffer ⇒ A})#F] { | |
override def forReal : (ByteBuffer) ⇒ Double = _.getDouble | |
override def forBoolean : (ByteBuffer) ⇒ Boolean = _.get != 0 | |
override def forString : (ByteBuffer) ⇒ String = ??? | |
override def forInteger : (ByteBuffer) ⇒ Int = _.getInt | |
} | |
/** | |
* Пример -- создание вычитывалки промежуточного хранилища | |
* Inference частично не справляется, подсветка в идее -- тоже | |
*/ | |
def usage(t : ModelicaType) : (ByteBuffer ⇒ Unit, ValueHolder[_]) = { | |
val holder = t(holderCreator) | |
val bufferReader = t[readerCreator.C](readerCreator) // Inference не справляется. Почему -- пока не понял | |
val reader = (b : ByteBuffer) ⇒ holder.lastValue = bufferReader(b) | |
(reader, holder) | |
} | |
/* Пример -- создание таггированной записывалки */ | |
case class FieldCallback[@specialized(Double,Int, Boolean) T : PModelicaType]( f : T ⇒ Unit ) { | |
val tag : PModelicaType[T] = implicitly | |
def apply(value : T) : Unit = f(value) | |
} | |
def printInt(n : Int) = println(n) | |
val a: FieldCallback[_] = FieldCallback(printInt) | |
def printUnit(n : Unit ) = println(n) | |
//Error: Cannot prove that Unit can be represented as Modelica type | |
//val b = FieldCallback(printUnit) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment