Разница между Haskell и Idris: отражение среды выполнения / Compiletime в юниверсах типов

таким образом, в Идрисе совершенно справедливо написать следующее.

item : (b : Bool) -> if b then Nat else List Nat
item True  = 42
item False = [1,2,3] // cf. https://www.youtube.com/watch?v=AWeT_G04a0A

без подписи типа, это выглядит как динамически типизированный язык. Но, действительно, Идрис зависимо-типизирован. Конкретный тип item b можно определить только во время выполнения.

это, конечно, Haskell-программист говорит: тип item b в смысле Idris задается во время компиляции, это if b then Nat ....

теперь мой вопрос: я прав, чтобы заключить, что в Haskell, граница между средой выполнения и временем компиляции проходит точно между миром значений (False, "foo", 3) и миром типов (Bool, String, Integer), тогда как в Idris граница между средой выполнения и временем компиляции проходит через вселенные?

кроме того, я прав, предполагая, что даже с зависимыми типами в Haskell (используя DataKinds и TypeFamilies, cf. в этой статье) приведенный выше пример невозможен в Haskell, потому что Haskell вопреки Идрису делает не допускать утечки значений на уровень типа?

2 ответов


Да, вы правы, заметив, что различие типов и значений в Idris не согласуется с различием compiletime-only против времени выполнения и compiletime. Это хорошо. Полезно иметь значения, которые существуют только в compiletime, так же, как в логике программ мы имеем "призрачные переменные", используемые только в спецификациях. Полезно также иметь представления типов во время выполнения, позволяя общее Программирование типов данных.

В Haskell, DataKindsPolyKinds) давайте пиши

type family Cond (b :: Bool)(t :: k)(e :: k) :: k where
  Cond 'True  t e = t
  Cond 'False t e = e

и в недалеком будущем мы сможем писать

item :: pi (b :: Bool) -> Cond b Int [Int]
item True  = 42
item False = [1,2,3]

но пока эта технология не будет реализована, мы должны иметь дело с одноэлементными подделками зависимых типов функций, например:

data Booly :: Bool -> * where
  Truey  :: Booly 'True
  Falsey :: Booly 'False

item :: forall b. Booly b -> Cond b Int [Int]
item Truey  = 42
item Falsey = [1,2,3]

вы можете получить довольно далеко с такой подделкой, но все было бы намного проще, если бы у нас была настоящая вещь.

важно, что план для Haskell состоит в том, чтобы поддерживать и отделять forall и pi, поддерживая параметрический и специальный полиморфизм, соответственно. Лямбды и приложения, которые идут с forall все еще может быть удален при генерации кода во время выполнения, как и сейчас, но для pi сохраняются. Также имеет смысл иметь абстракции типа времени выполнения pi x :: * -> ... и бросить крысиное гнездо сложности, что Data.Typeable в помойку.


теперь мой вопрос: прав ли я, чтобы заключить, что в Хаскелле граница между средой выполнения и compiletime выполняется точно между миром значений (False," foo", 3) и мира типов (Bool, String, Integer), тогда как в Idris граница между средой выполнения и compiletime идет через вселенные?

Идрис компилируется в эпос (обновление: нет, он больше не компилируется в Epis как Спирмена говорит в комментарии ниже):

нет семантической проверки, кроме как посмотреть, находятся ли имена в области - - - это предполагается, что язык более высокого уровня будет выполнен проверка типов, и в любом случае Epic не должен делать никаких предположений о система типов более высокого уровня или любые примененные преобразования. Аннотации типа необходимы, но они дают только подсказки компилятор (я мог бы изменить это).

так типы не важно denotationally, то есть значение термина не зависит от его типа. Кроме того, некоторые вещи уровня ценности могут быть стерты, например, в Vect n A (где Vect - тип списков со статически известной длиной)n (длина) можно стереть,, потому что

есть методы, описанные Брэди, Макбрайд и Маккинна в BMM04 чтобы удалить индексы из структур данных, используя тот факт, что функции, работающие на них либо уже имеют копию этот при необходимости можно быстро восстановить соответствующий индекс или индекс.

дело вот в чем pi В Идрисе действует для типов почти так же, как forall в Haskell: они оба параметрические (хотя эти параметры различны) в этом случае. Компилятор может использовать типы для оптимизации кода, но в обоих языках, регулирование потока не зависит от типов, т. е. вы не можете сказать if A == Int then ... else ... (хотя, если A находится в канонической форме, то вы статически знаю будь то Int или нет, и, следовательно,можете написать A == Int, но это все равно не влияет на поток управления, потому что все решения принимаются до выполнения). Конкретный тип item b не имеет значения во время выполнения.

но как pigworker говорит, что это не обязательно параметрического типов. А также не обязательно быть непараметрическим по значениям. Тип-уровень-значение-уровень и параметрический-непараметрический полностью ортогональны дихотомии. См.этой ответ для деталей.

таким образом, Haskell и Idris отличаются тем, как они относятся к вещам уровня значения wrt runtime/compile content (потому что в Idris вы можете пометить аргумент с . чтобы сделать его стираемым), но они относятся к типам примерно одинаково.