В настоящее время я пытаюсь определить модель синхронизированного языка потока данных в scala.scala зависимые от типов типы и доказательства уровня типа
Поток фактически представляет собой бесконечную последовательность значений некоторого типа T, перемещаемую некоторыми часами C (часы показывают, в какие моменты поток фактически доступен).
Сэмплированный поток SF может быть получен из потока F путем отбора его в соответствии с самой синхронизацией C, полученной из другого (булева) потока F ': SF содержит значения F, отсчитываемые, когда логический поток F' истинен.
«Базовые часы» - это часы, полученные из всегда истинного потока с именем «T».
В приведенном ниже примере, Р и Р «находятся на базовой частоте (и - используется, чтобы показать, что поток не имеет значения в некоторый момент времени)
T : 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ... (always 1)
F : 0 0 0 1 1 1 0 1 0 1 0 0 0 1 1 1 1 ...
F' : 0 1 0 0 0 1 0 1 1 1 0 0 0 1 0 0 1 ...
F sampled on F': - 0 - - - 1 - 1 0 1 - - - 1 - - 1 ...
так (F пробы на F») принимает значение F, когда F 'истинно, и не определено, когда F' ложно.
Цель состоит в том, чтобы сделать эту взаимосвязь выборки очевидной в типе потоков и выполнять статические проверки. Например, разрешите только пробовать поток из другого, если они находятся на одних и тех же часах. (Это для DSL для моделирования цифровых схем).
Система, о которой идет речь, является системой, зависящей от типа, потому что часы являются частью типа потока и сами производятся из значения потока.
Поэтому я попытался смоделировать это в scala, используя типы, зависящие от пути, и получить вдохновение из бесформенного. Часы моделируются типами следующим образом:
trait Clock {
// the subclock of this clock
type SubClock <: Clock
}
trait BaseClock extends Clock {
type SubClock = Nothing
}
Это определяет тип часов и конкретные часы, базовую частоту, которая не имеет subclock.
Затем я попытался смоделировать потоки:
trait Flow {
// data type of the flow (only boolean for now)
type DataType = Boolean
// clock type of the flow
type ClockType <: Clock
// clock type derived from the Flow
class AsClock extends Clock {
// Subclock is inherited from the flow type clocktype.
type SubClock = ClockType
}
}
я определил внутренний класс в черте потока, чтобы быть в состоянии поднять поток на часы, используя зависимые пути типов. если f - поток, f.AsClock - тип Clock, который может использоваться для определения выборочных потоков.
Тогда я обеспечиваю способы построения потоков на базовой частоте:
// used to restrict data types on which flows can be created
trait DataTypeOk[T] {
type DataType = T
}
// a flow on base clock
trait BFlow[T] extends Flow { type DataType = T; type ClockType = BaseClock }
// Boolean is Ok for DataType
implicit object BooleanOk extends DataTypeOk[Boolean]
// generates a flow on the base clock over type T
def bFlow[T](implicit ev:DataTypeOk[T]) = new BFlow[T] { }
До сих пор так хорошо. Тогда я обеспечиваю Ваты построить выборочную поток:
// a flow on a sampled clock
trait SFlow[T, C <: Clock] extends Flow { type DataType = T; type ClockType = C }
// generates a sampled flow by sampling f1 on the clock derived from f2 (f1 and f2 must be on the same clock, and we want to check this at type level.
def sFlow[F1 <: Flow, F2 <: Flow](f1: F1, f2: F2)(implicit ev: SameClock[F1, F2]) = new SFlow[f1.DataType, f2.AsClock] {}
Это где значение потока поднимается до типов с использованием f2.AsClock.
Идея заключается в том, чтобы иметь возможность написать что-то вроде этого:
val a1 = bFlow[Boolean]
val a2 = bFlow[Boolean]
val b = bFlow[Boolean]
val c1: SFlow[Boolean, b.AsClock] = sFlow(a1, b) // compiles
val c2: SFlow[Boolean, b.AsClock] = sFlow(a2, b)
val d: SFlow[Boolean, c1.AsClock] = sFlow(a1, c1) // does not compile
и есть компилятор отвергает последний случай, потому что ClockType от a1 и c1 не равны (a1 на базе часы, c1 находится на часах b, поэтому эти потоки не находятся на одних и тех же часах).
Так что я представил (неявное эв: SameClock [F1, F2]) аргумент к моему методу строителя, где
SameClock является признаком означал свидетель во время компиляции, что два потока имеет одинаковый ClockType, и что правильно пробовать первый, используя часы, полученные из второго.
Здесь я совершенно не знаю, как действовать. Я посмотрел исходный код Nat и HList в бесформенном виде и понял, что объекты, свидетельствующие об этих фактах, должны быть построены в структурном форвардном индуктивном режиме: вы предоставляете неявные сборщики для объектов, запускающих конструктор этого типа для типов, которые вы хотите статически проверять и механизм неявного разрешения генерирует объект, свидетельствующий об этом свойстве, если это возможно.
Однако я действительно не понимаю, как компилятор может построить правильный объект с использованием форвардной индукции для экземпляра любого типа, поскольку мы обычно делаем доказательства с использованием рекурсии, деконструируя термин в более простых терминах и доказывая более простые случаи.
Некоторые рекомендации от кого-то с хорошим пониманием программирования на уровне шрифтов были бы полезны!
Тип вывода фактически работает в обратном порядке: он ищет неявки, которые могут обеспечить правильный тип, а затем для имплицитных запросов, aban пожертвование поиска, если типы становятся «большими». В этом конкретном случае вам, вероятно, понадобится скалаз 'Leibniz. ===', равенство типа. – lmm
Спасибо, я попробую. – remi
Любые преимущества использования scalaz Leibniz. === над встроенным =: = (похоже, работает в моем случае)? – remi