Skip to content

Instantly share code, notes, and snippets.

@p-pavel
Last active February 25, 2017 13:06
Show Gist options
  • Save p-pavel/36cfe1c772bc3cd454a96545f781a313 to your computer and use it in GitHub Desktop.
Save p-pavel/36cfe1c772bc3cd454a96545f781a313 to your computer and use it in GitHub Desktop.
Solving tagged types problem with elimination
/** Для решения проблемы с тем, что 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