Re[2]: [Зависимые типы] Объясните на пальцах.
От: BulatZiganshin  
Дата: 01.07.09 18:27
Оценка: 1 (1) +1 :))) :))) :))) :)
Здравствуйте, WolfHound, Вы писали:

WH>Теперь если компилятор не будет уверен что в эту функцию передают списки одинаковой длинны то программа не скомпилируется.


... и процесс написания программы выглядит как сдача экзамена

компилятор: а это вы откуда вывели?
юзер: ну вот, если эпсилон равен гамме, то Юпитер в фазе Венеры..
компилятор: докажи!
Люди, я люблю вас! Будьте бдительны!!!
Re[9]: [Зависимые типы] Объясните на пальцах.
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 07.07.09 03:59
Оценка: -1 :))) :)
Здравствуйте, VladD2, Вы писали:

VD>А вот для человека важна простата понимания.


Анатомические открытия на rsdn.ru!
(простите, не удержался)
Re[9]: [Зависимые типы] Объясните на пальцах.
От: deniok Россия  
Дата: 03.07.09 22:38
Оценка: 44 (3)
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, deniok, Вы писали:


D>>Мечта — это чтобы программы сами писались?

D>>Зависимые типы позволяют довольно удобно записывать широкий класс спецификаций. Например, отсортированный список на Агде можно описать так:
D>>
D>>data OList : Nat -> Set where 
D>>  Nil  : {b : Nat} -> OList b 
D>>  Cons : {b : Nat} -> (x : Nat) -> (b ≤ x) -> OList x -> OList b
D>>


VD>Сначала хочется пояснить для тех кто в курсе этой агрды, что для непосвященных это не более чем кракозябры. Все эти Nat-ы и Set-ы просто не определенные понятия. Так что хотите кому-то что-то объяснить, разжёвывайте по мельче.


Set, грубо говоря, тип всех типов. Если мы хотим сказать, что идентификатор A — это тип, мы пишем A : Set. Nat — это натуральные числа, определенные в стандартной библиотеке так
data Nat : Set where
 zero : Nat
 suc  : Nat -> Nat

Дальше над ними определяется сложение (подчеркивания — плэйсхолдеры для аргументов оператора)
_+_ : Nat -> Nat -> Nat
 zero  + m = m
 suc n + m = suc (n + m)

умножение и т.д. Определения строятся на паттерн матчинге.

Тип натуральных чисел идеален для индексирований, в том числе и на уровне типов. Например, обычный список мы бы определили в Агде так
data List (a : Set) : Set where
 []   : List a 
 _::_ : a -> List a -> List a

А список, индексированный длиной, можно определить так
data List (a : Set) : Nat -> Set where
 []   : List a zero
 _::_ : {n : Nat} -> a -> List a n -> List a (suc n)
Re[11]: [Зависимые типы] Объясните на пальцах.
От: deniok Россия  
Дата: 04.07.09 11:32
Оценка: 41 (3)
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, Alexey Romanov, Вы писали:


AR>>Но нам ничто не мешает написать функцию

AR>>
AR>>zip' : (Vec A n) -> (Vec B m) -> (Vec (A,B) (min n m))
AR>>

AR>>которая соответствует второму варианту VladD2.
D>Нам то ничего не мешает написать все что угодно, но поинт то был в том что бы zip принимал только списки одинаковой длинны и ругался при компиляции если это не так.

Ну именно так всё и есть. Ты не можешь встроить вызов zip в то место, где нет статической гарантии "равнодлинности" векторов-параметров. Если их нет, то ты либо должен обеспечить такие гарантии ручками (скажем, обеспечив механизм параллельного чтения элементов списка из файлов, по построению гарантирующего равную длину векторов), либо пользоваться версией zip', которая игнорирует хвост длиннейшего.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 09:44
Оценка: 39 (1) +1 -1
Здравствуйте, BulatZiganshin, Вы писали:

BZ>ты можешь *доказать*, что некая программа не содержит багов?


Это зависит от того, что такое "баг".

Программа она же дура. Она делает, что ей скажут. Что написано, то и сделала -- с этой точки зрения багов не просто нет, их практически не существует, кроме сбоев аппаратуры.

Баг это отличие программы от спецификации. Или отличие спецификации от "того, что имелось ввиду". Имея на руках только программу ни то ни другое доказать невозможно. Если есть формальная спецификация, по которой можно что-то доказывать, то скорее всего её можно формально и преобразовать в программу, т.е. "формальная спецификация" это программа и есть. Осталась только разница между спецификацией и мечтой, и вот она видимо неустранима и соответствие не доказать.

Но иногда можно доказать какие-нибудь параметры, типа того, что никогда не виснет, или что задержка при ответе не больше чем, и т.п. Но это не "отсутствие багов".
Делай что должно, и будь что будет
Re: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 01.07.09 17:40
Оценка: 23 (3)
Здравствуйте, dotneter, Вы писали:

D>Кто нибудь может в пяти строчках кода и паре предложений выразить суть и

Суть в том что с типом связываются значения времени исполнения.
Например:
data Vec (A : Set) : Nat -> Set where
  [] : Vec A zero
  _::_ : {n : Nat} -> A -> Vec A n -> Vec A (suc n)

В данном случае описывается список тип которого параметризован не только типом элементов содержащихся в списке но и длинной этого списка.
Первый конструктор создает пустой список с типом которого связано значение 0.
Второй конструктор интереснее.
Первый (неявный) аргумент это длинна исходного списка.
Второй элемент.
Третий исходный список с типом которого связанна длинна.
И с результатом связанна длинна исходного списка плюс один.

D>основные бенефиты идеи?

Например мы хотим написать функцию которая принимает два списка одинаковой длинны и возвращает список кортежей.
Сигнатуру функции можно описать так:
zip : {n : Nat} -> {A : Set} -> {B : Set} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n

Теперь если компилятор не будет уверен что в эту функцию передают списки одинаковой длинны то программа не скомпилируется.
Если программа скомпилируется то Компилятор также будет в курсе что тот список что вернула данная функция равен по длине двум исходным.

Это позволяет доказывать кучу утверждений и как следствие не писать код обработки подавляющего большинства нештатных ситуаций ибо их просто не может быть.
Как следствие если не лениться писать правильные типы то можно избавиться не только от кучи проверок в функции на тему, а не подсунули ли нам какую гадость и что делать если таки подсунули, но и юнит/интеграционных тестов ибо система типов их перекрывает с большим запасом.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.07.09 22:24
Оценка: 2 (1) +1
Здравствуйте, dotneter, Вы писали:

VD>>Вопрос только в одном, на сколько это сложнее обычоного подхода. Судя по приведенной кракозябре, намного.

D>А что это за обычный подход который рубит половину багов на этапе компиляции?

Статическая верификация кода возможна и так. Вон в 4-ом фрэйворке вроде как будет поддерживаться для реальных систем.

Что до багов, то они никуда не исчезнут. В этом вопросе нет волшебной палочки. Баги сазажают люди. Если алгоритм крив, то никакая верификция или мощная система типов не спасет. Не надо обольщаться.

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

Так что мощная система типов — это конечно хорошо, но только при том условии, что при этом она не усложнит решение задачи.
Ну, а то что мы тут увидели вряд ли можно назвать простым.

В прочем, возможно я "не догоняю".
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 13:52
Оценка: 1 (1) -1
А>>Во всяком случае, без дополнительного изучения, так однозначно отвергать эту штуку не стоит,
VD>Дык я давно вырос из возраста когда отвергают все и вся с пеной изо рта, и пока не дожил до возраста когда скептически скрипят на все подряд.

I've come up with a set of rules that describe our reactions to technologies:
1. Anything that is in the world when you're born is normal and ordinary and is just a natural part of the way the world works.
2. Anything that's invented between when you're fifteen and thirty-five is new and exciting and revolutionary and you can probably get a career in it.
3. Anything invented after you're thirty-five is against the natural order of things.
— Douglas Adams


Сколько тебе лет?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[11]: [Зависимые типы] Объясните на пальцах.
От: VoidEx  
Дата: 07.07.09 22:11
Оценка: 1 (1) +1
Здравствуйте, VladD2, Вы писали:

VD>Более того. Ну, представим компилятор заставил меня обрабатывать какие-то несоответствия. ОК. А как я их обработаю? Ну, не сошлась у меня длинна двух списков перед вызовом zip-а. И что мне делать? Исключения кидать? Дык, а зачем я тогда пишу код проверок? Пусть его кидает сам zip.

VD>Писать какой-то код реакции? Дык это может резко увеличить объем работы и при этом один хрен многие схалтурят и напишут какую-нибудь ересь.

Эм, а без зависимых типов ты как с такими бедами справляешься? Оставляешь на самотёк что ли?
Re[16]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 12:58
Оценка: +1 :)
Здравствуйте, dotneter, Вы писали:

SH>>Тогда, я считаю, багов не существует в природе. Можешь привести пример бага?

D>
D>sum x y = x - y
D>


Это не баг. Это была нужна функция x — y. Потребуется другая -- будет написана sum2.
Делай что должно, и будь что будет
Re[4]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 13:11
Оценка: +2
Здравствуйте, Аноним, Вы писали:

А>Это если считать обычным подходом код без модульных тестов и без проверок параметров функции. Если первое неплохо автоматизируется с помощью того же PEX (сам пока не пользовался, но допустим), то от второго, вроде как, никуда не денешься. Хотя, на первый взгляд, да, действительно громоздко.


Вот именно. Очень громоздко и на тот самый первый взгляд (как минимум) невнятно.

А>Во всяком случае, без дополнительного изучения, так однозначно отвергать эту штуку не стоит,


Дык я давно вырос из возраста когда отвергают все и вся с пеной изо рта, и пока не дожил до возраста когда скептически скрипят на все подряд.

Потенциально идея введения в систему типов чего-то что позволит повысить контроль за кодом и тем более избавиться от юнит-тестрв и контроля за параметрами. Но это при том условии, что сложность вносимая дополнительными описаниями не будет превышать сложности описания ассертов и тех самых юнит-тестов.

К тому же я практически уверен, что юнит-тесты от этого не исчезнут. Юнит-тесты проверяют поведение, а описать поведение статически просто невозможно. Это и есть код.

А>или за твоими словами кроется некий опыт использования/изучения этого подхода? В таком случае, было бы очень интересно услышать подробности.


С данным подходом я не сталкивался. Я возился с системами доказательства корректности ПО. Это не тоже самое, но преследует схожие цели.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 14:04
Оценка: +2
Здравствуйте, BulatZiganshin, Вы писали:

BZ>ты можешь *доказать*, что некая программа не содержит багов?


Я могу доказать обратное.

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

Что мне толку со знания о корректности кода если на его написание я потратил в 10 раз больше чем я потратил бы на его написание и отладку традиционными средствами?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 14:55
Оценка: +2
Здравствуйте, deniok, Вы писали:

D>Мечта — это чтобы программы сами писались?

D>Зависимые типы позволяют довольно удобно записывать широкий класс спецификаций. Например, отсортированный список на Агде можно описать так:
D>
D>data OList : Nat -> Set where 
D>  Nil  : {b : Nat} -> OList b 
D>  Cons : {b : Nat} -> (x : Nat) -> (b ≤ x) -> OList x -> OList b
D>


Сначала хочется пояснить для тех кто в курсе этой агрды, что для непосвященных это не более чем кракозябры. Все эти Nat-ы и Set-ы просто не определенные понятия. Так что хотите кому-то что-то объяснить, разжёвывайте по мельче.

D>Теперь функция с типом

D>
D>sort : List Nat -> OList 0
D>

D>либо не компилируется, либо гарантированно возвращает отсортированное.

Замечательно. И как будет выглядеть описание скажем функции получающей на входе текстовый файл, и выдающей на выходе АСТ распознанного языка и/или список ошибок? И что это описание может доказать?
Другими словами, какова практическая ценность данного подхода?

А то примитивы вроде функции сортировки и так проверяются на раз. А пишутся они очень редко.

Сложность же начинается там где есть огромные объемы входных данных, большое количество параметров чье сочетание дает очень разнообразный результат, а некоторые из сочетаний не имеют смысла. В таких условиях многие граничные ситуации просто игнорируются программистом и не получают должного уровня обработки, что в некоторых случаях вылезает в виде багов во время исполнения.
Так вот проблем не в том, что эти случаи сложно обработать, а в том, что код их обработки во много раз увеличивает общий код приложения. И если ссистема типов начнет заставлять меня обрабатывать все подобные случаи, то я заплачу и убегу .
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 15:25
Оценка: +2
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, thesz, Вы писали:


VD>>>К тому же я практически уверен, что юнит-тесты от этого не исчезнут. Юнит-тесты проверяют поведение, а описать поведение статически просто невозможно. Это и есть код.


T>>Боже ж мой.

T>>Код и есть статическое описание поведения.
T>>То есть, мы статически — кодом, ведь код-то не меняется во время исполнения, — описываем поведение программы.
T>>Таким образом, поведение описывается исключительно статическим образом. Даже если это тесты.

G>Ты видимо не понял. Если можно написать спецификацию поведения некоторого объекта, то эта спецификация будет не проще самого кода объекта, вероятнее всего гораздо сложнее.


"Вероятней всего" — это откуда такая оценка? Есть исследования?

G>Как потом доказать что спецификация написана без ошибок?


Есть такая штука, называется тройки Хоара. Выглядят так:
{Q} S {P}

Лет этой штуке не счесть.

С её помощью были разработаны многие алгоритмы, часто весьма и весьма нетривиальные.

Есть такая книга, Program Construction: calculating implementation from specification, которая рассказывает про то, как применять тройки Хоара к реальным задачам.

По чтению этой книги у меня сложилось впечатление, что большая часть реализации вытекает из внешней спецификации и спецификаций на доступные компоненты. Вытекает сама собой, просто при рассуждении оказывается так, что в большинстве мест могут быть подставлены только вполне определённые компоненты. Другие просто не подходят.

Моментов ключевого выбора раз, два и обчёлся.

Если ты посмотришь на свои программы и на то, как ты их создаёшь, то ты обнаружишь ровно то же самое.

Поэтому я крайне скептически отношусь к заявлениям, что спецификация может быть сложней самого кода.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[9]: [Зависимые типы] Объясните на пальцах.
От: Alexey Romanov  
Дата: 04.07.09 09:54
Оценка: +1 :)
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, thesz, Вы писали:


D>Непонимать. Еще раз

listA = getListA (void -> Vec A n)
listB = getListB (void -> Vec B n)

zip listA listB // как тут компилятор понимает какой длинны listA и listB

D>(Вместо чтения из файла может быть все что угодно)

D>Делаем равное количетсво записей в listA.txt и listB.txt программа копилируется,

D>меняем на не равное, не компилируется, так?

Во-первых, код будет выглядеть скорее так:
do
  listA <- getListA : IO (Vec A n) //побочные эффекты в IO
  listB <- getListB : IO (Vec B n) //

  ... zip listA listB ... // и что-то с этим результатом будем ещё делать


Откуда взялась переменная n? Если она уже определена выше, и строчки с listA и listB скомпилировались, то компилятор уже знает, что listA и listB имеют одинаковую длину.

Если имеется ввиду, что getListA имеет тип IO (Vec A n), то это сокращённая запись для {forall A n}(IO (Vec A n)), то есть getListA обещает вернуть список любой длины и любого типа, который нужен. Естественно, чтение из файла такого типа иметь не будет. А будет оно иметь тип
IO {exists n}(Vec A n)
IO {exists n}(Vec B n)

То есть возвращается список некоторой натуральной длины. Естественно, эти n могут быть разными.

Но нам ничто не мешает написать функцию
zip' : (Vec A n) -> (Vec B m) -> (Vec (A,B) (min n m))

которая соответствует второму варианту VladD2.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: Alexey Romanov  
Дата: 06.07.09 21:28
Оценка: 39 (1)
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, WolfHound, Вы писали:


WH>>Здравствуйте, VladD2, Вы писали:


VD>>>Многословность != непонятность. Сравним два варианта:

VD>>>
VD>>>zip : {n : Nat} -> {A : Set} -> {B : Set} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
VD>>>

VD>>>и
VD>>>
VD>>>zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
VD>>>  requires l1.Lenght == l2.Lenght
VD>>>  ensures  value.Lenght == l1.Lenght
VD>>>

WH>>Сравнил. Мне первый понятнее.

VD>Ну, что же. Можешь радоваться, так как ты вместе с еще 3 человеками сможешь в этом во всем разбираться.

VD>Лично я очень не хотел бы по пол часа въезжать в объявление примитивной функции. Все же граничные условия — это дело десятое. Контролировать их конечно полезно, но знать о них чтобы программировать не обязательн.

WH>>Более того он формален в доску чего не скажешь о костылях во втором случае.


VD>Формальность — это хорошо для компьютера, или для писателя компилятора. А вот для человека важна простата понимания.


VD>Так что нужно или придумать более простой синтаксис, или придумать как извлекать такие сложные описания из мене формальных описаний ограничений.


Синтаксис этот скорее непривычный, чем сложный.

В первом случае мы имеем просто тип. Во втором -- тип отдельно, условия отдельно.

VD>>>Приведенный тобой пример описания типа функции в двое длиннее тела функции и в 10 раз не понятнее (на мой взгляд).

WH>>Ну давай запишем это в более привычном тебе виде:
WH>>
WH>>zip{A, B, n}(l1 : Vec A n, l2 : Vec B n) : Vec (A * B) n
WH>>

WH>>С синтаксисом можно обходится весьма вольно.

VD>Я не сказал бы, что приведенный пример привычен, но он куда короче и понятнее (но без домысливания не обойтись). Отличие B от n без пояснений не видать. Плюс не ясно, что такое Vec? Ну, и синтаксис тоже весьма привычный.

VD>Возможно как-то так было бы понятнее:
VD>
VD>zip[A, B, len : int](l1 : list[A, len], l2 : list[B, len]) : list[A * B, len]
VD>

VD>В прочем — это тоже довольно громоздко.

Это приемлемо. Но учитывая, что квадратные и круглые скобки различают только выводимые и явные параметры, а не параметры типов и функций. Так что скорее

zip[A : Type, B : Type, len : int](l1 : list(A, len), l2 : list(B, len)) : list(A * B, len)

Type вместо агдовского Set. int тут тоже в общем-то не при деле, поскольку списков с отрицательной длиной не бывает -- но это ладно. Единственная причина, по которой в C#/Nemerle/Haskell не нужно указывать, что A и B типы -- это отсутствие других возможностей. Можно попробовать грязный хак вроде "все параметры функции или типа, тип которых не указан, имеют тип Type", но идея так себе.

VD>Ну и вопрос о то, что будет в случае динамического формирования списка так же остается открытым. Как проверить тело по сигнатуре в обще ясно, но как проверить все вызовы этого метода?


VD>Например, при описании списка мы указываем, что у него есть один неявный параметр типам целочисленного типа, и что он связан со значением свойства Length. Тогда приведенный пример можно было бы описать очень просто и изящно:

VD>
VD>zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
VD>  types invariant l1.Lenght = l2.Lenght = result.Lenght
VD>{
VD>  ...
VD>}
VD>

VD>Это было бы и кратко, и понятно не посвященным.
В "инвариантах" может быть далеко не только равенство, а любые условия. Так что скорее инвариант должен выглядеть как
l1.Length == l2.Length, l1.Length == result.Length
Уже хуже.

Неявные параметры для типов -- это понятно непосвящённым? Почему неявный параметр -- именно длина, а не (например) первый элемент списка? Мне не хотелось бы каждый раз раз лезть в определение списка и выяснять, какие свойства можно использовать в инвариантах, а какие -- нет.

Давай ещё сделаем A и B неявными:
zip(l1 : list, l2 : list) : list
types invariant l1.Length == l2.Length, l1.Length == result.Length,
value.Type == l1.Type * l2.Type
{
...
}
[/c#]
По-моему, это не стало ни понятнее, ни короче. Точно так же вариант с длиной как неявным параметром мне не нравится.

VD>Ну, так дава начнем с объяснения того как статические проверки будут работать для динамически получаемых данных.

VD>Скажем есть у нас функция возвращающая список введенных пользователем чисел:
VD>
GetData[int, n : int]() : list[int, n]


Эта функция обещает вернуть список любой нужной длины. Функция, которая возвращает список некоторой неизвестной длины, может иметь тип
GetData() : (n : int) * list(int, n)

либо использовать старый тип для списков произвольной длины (который, естественно, никуда не денется от расширения системы типов).

VD>и есть твой Zip:

VD>
Zip[A, B, len : int](l1 : list[A, len], l2 : list[B, len]) : list[A * B, len]

VD>И мы пишем:
VD>
VD>def res = Zip(GetData(), GetData());
VD>WriteLine(res);
VD>

VD>Как на это отреагирует компилятор?

С твоим вариантом GetData? Это зависит от того, есть ли правила для значений неявных параметров по умолчанию, когда их не удаётся вывести. Если да, то он выведет неявные параметры так:
def res : list[int * int, 0] = Zip[int, int, 0](GetData[0](), GetData[0]());
WriteLine(res);

Если нет, то выдаст ошибку из-за невозможности вывода длины.

С нормальным GetData -- нужно сначала исправить программу. В частности, если используем выриант
def (n,data1) = GetData(); // data1 : list(int, n)
def (m,data2) = GetData(); // data2 : list(int, m)
def res = Zip(GetData(), GetData());
WriteLine(res);

то вывод типов не пройдёт. Но это ровно то, что нам и нужно. Весь смысл зависимой типизации Zip в том, чтобы не допустить применения к спискам разной длины. А эти списки очевидно могут быть разной длины.

VD>Если не даст скомпилировать, то как нам написать рабочий вариант?


А для этого нужно решить, что считать рабочим вариантом. Как эта функция должна себя вести, если списки имеют разную длину?

1. Выдать исключение.
2. Отбросить "лишние" элементы из более длинного списка.

Скажем, второй.
Zip1[A : Type, B : Type, n : int, m : int](l1 : list[A, n], l2 : list[B, m])
{
  def k = min(n, m);
  def l1' = Take(l1, k);
  def l2' = Take(l2, k);
  return Zip(l1', l2');
}

Main() : void
{
  def (_,data1) = GetData();
  def (_,data2) = GetData();
  def res = Zip1(GetData(), GetData());
  WriteLine(res);
}


Это проходит проверку типов: в Zip1 компилятор знает, статически, что: k <= n, k <= m, l1' и l2' имеют длину k и поэтому к ним можно применить Zip; в Main компилятор знает, что Zip1 применимо к любым спискам.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 07.07.09 09:09
Оценка: 9 (1)
VD>Вот если бы эти зависимости можно было выражать как-то по другому...
VD>Например, при описании списка мы указываем, что у него есть один неявный параметр типам целочисленного типа, и что он связан со значением свойства Length. Тогда приведенный пример можно было бы описать очень просто и изящно:
VD>
VD>zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
VD>  types invariant l1.Lenght = l2.Lenght = result.Lenght
VD>{
VD>  ...
VD>}
VD>

VD>Это было бы и кратко, и понятно не посвященным.

Ты придираешься к конкретным вещам, упуская из виду общие.

То, о чём ты говоришь, навевает мысли о так называемом экстенсиональном равенстве. У нас списки имеют общие свойства (длины совпадают), типы связаны A -> B -> (A,B) и на всё остальное мы не смотрим. Такой вид рассуждений приводит к принципиально неразрешимому (undecidable) алгоритму проверки зависимых типов. Что приведёт к необходимости отключать части проверяющего алгоритма, чтобы он хоть как-то работал, и к возможности протянуть ошибку в рассуждениях.

Современные проверяльщики зависимых типов данных работают с интенсиональным равенством. Для них a+b не равно b+a.

Да, это сложней. Но это даёт возможность быть правым всегда, когда с тобой согласен механический аппарат под названием компилятор.

Ситуация улучшается. Недавно придумали так называемое наблюдаемое (observational) равенство. Для него a+b равно b+a.

Я думаю, придумают и ещё что-то.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[7]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 07:16
Оценка: 6 (1)
Здравствуйте, VladD2, Вы писали:

VD>>>А вот со статической проверкой будут проблемы, так как списки могут формироваться динамически, и их длинна, в общем случае, не известна во время компиляции.

WH>>Прелесть зависимых типов в том что они прекрасно работают в данном случае...

VD>Делов в том, что подобные ответы не имеют практического смысла. Это не более чем сотрясение воздуха. Понимания у окружающих, да и твоей правоты это не прибавляет.


Аналогия — для того, чтобы написать функцию, складывающую два числа, нам не нужно знать точные значения, которые будут в неё передаваться. Нам достаточно декларировать, что они оба являются числами. Так и здесь — для того, чтобы написать функцию склеивания двух списков, нам достаточно декларировать, что они имеют одинаковую длину. Если это не так (или компилятор не сможет доказать) — компиляция не пройдёт. Поэтому для общего случая эта функция работать не будет. Она будет работать только для случаев, когда у списков одинаковые длины.

VD>>>Я повторюсь, но мне не понятно, как компилятор сможет проверить работу со списками большая часть которых получается динамически?

VD>>>Или мы будем работать отдельно с динамическими списками (и при этом все проверки пойдут на смарку), и отдельно со статическими?
WH>>Ты точно не понял что к чему.
VD>Ну, так поясни, а не декларируй никому не интересные вещи о моем понимании.

Есть разные способы, например, мы можем написать функцию, проверяющую — одинаковая ли длина у списков, и если одинаковая вызвать нашу функцию склейки. Компилятор это дело пропустит, т.к. в данном месте будет доказано, что у списков одинаковая длина.

VD>Сложно. Много шума. Это видно очень отчетливо. Возможно все тоже самое можно было бы записать в несколько раз проще.


Тут ещё не раз не показали как это можно сделать. А то, что зависимые типы сокращают и упрощают код было уже показано несколько раз.

VD>Но в таком виде функцию по сложнее уже будут воспринимать далеко не все.


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

P.S. Зависимые типы — это следующий шаг после Хиндли-Милнера, который есть следующий шаг после статической типизации
Re[5]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 06.07.09 08:38
Оценка: 4 (1)
Здравствуйте, VladD2, Вы писали:

WH>>
WH>>zip : forall{A B n} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
WH>>


VD>Кстати, так уже намного лучше. Это гипотетический синтаксис или Агда?


VD>Не ясно только зачем нужен "forall{A B n} -> ". Это объявление явно лишнее и сбивает с толку.


Ну, вот видишь Vec, он с внешнего контекста, т.е. определён где-то снаружи, а forall говорит, что типы A,B,n искать снаружи не надо — это типы-переменные. Пример — В Haskell forall не пишется потому, что типы-переменные выделяются синтаксически — у них первая буква строчная. Т.е. это вопрос синтаксиса. Вполне возможен синтаксис, когда forall писать не обязательно — нашёл снаружи тип с таким именем — значит, это конкретный тип, не нашёл — тип-переменная. Но по вполне понятным причинам такой синтаксис нам не нужен :-)
Re[20]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 14:19
Оценка: 2 (1)
Здравствуйте, dotneter, Вы писали:

D>Я надеялся что мы еще в контексте предыдущего примера.


Да не вопрос. Я просто воспользовался удачно подвернувшимся случаем

D>Это баг спецификации а не реализации.


А в чём разница?
Особенно, если мы умеем спецификацию формально преобразовывать в реализацию?

Реализация более верхнего уровня это спецификация для более нижнего. Реализация на С это спецификация для компилятора. Машинный код, генерируемый компилятором это спецификация для процессора. Микрокод инструкции это спецификация для кусочков процессора... Ниже, пожалуй некуда, ниже сильно всё меняется, да и про микрокод я уже не уверен.

Но тем не менее, ошибка в любом из уровней это баг. Только в одном случае это проектировщики проектировали, проектировали, да не выпроектировали, во втором -- програмисты программировали да не выпрогрммировали, в третьем -- компиляторы не выкомпилировали и т.п. Даже если мы всё доказали кроме первого уровня, что безусловно огромное достижение, сказать, что в программе "багов нет и это доказано" нельзя.

Можно доказать соответствие модели. Нарисовать конечный автомат какой-нибудь Доказать, что в нём нет каких-нибудь плохих путей. Или что все пути обладают каким-то свойством и т.п. Но _доказать_ соответствие модели задаче невозможно. Математика, как и возможность доказательства, _начинается_ с модели. На предшествующем этапе нет ни математики ни доказательства. Модель можно только опровергнуть. В положительную строну -- можно поставить много экспериментов и убедиться, что результаты правильные. Но ведь это не доказательство.
Делай что должно, и будь что будет
Re[2]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.07.09 18:32
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

WH>
WH>zip : {n : Nat} -> {A : Set} -> {B : Set} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
WH>


WH>Как следствие если не лениться писать правильные типы то можно избавиться не только от кучи проверок в функции на тему, а не подсунули ли нам какую гадость и что делать если таки подсунули, но и юнит/интеграционных тестов ибо система типов их перекрывает с большим запасом.


Вопрос только в одном, на сколько это сложнее обычоного подхода. Судя по приведенной кракозябре, намного.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 11:04
Оценка: +1
Здравствуйте, dotneter, Вы писали:

Давайте выделим ветку? И в философию её... Оффтоп идёт.

D>Даже для

D>
D>sum x y = x + y
D>

D>?

Для доказательства нужно формально сравнить "что хотелось" и "что получилось". Проблема в том, что "что хотелось" в формальном виде отсутствует.

Если нужен пример, когда стандартное компьютерное сложение работает неинтуитивно -- возьми число с плавающей точкой побольше, и прибавь к нему 1. Не знаю, как в Хаскеле, в Питоне используются стандартные double из С, со всеми вытекающими. Плавающего числа около 10^17 должно быть достаточно...

Подразумевал ли автор, что ему нужно складывать такие числа? А кто его знает. Формальных критериев нет. С другой стороны, это ограничение не функции, а типа данных. А как должна вести себя функция, нарвавшись на такое ограничение? Опять непонятно. Может она правильно себя ведёт, а может подразумевалось что-то другое.

А я собственно намекаю, что "что хотелось" это принципиально неформализуемое понятие. Потому что когда оно формализовано это уже другая сущность -- спецификация. В процессе формализации что-то может потеряться, и формальным способом это потерявшееся не найти.
Делай что должно, и будь что будет
Re[14]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 12:25
Оценка: :)
Здравствуйте, dotneter, Вы писали:

SH>>Вдруг тебе понадобится ...

D>Будет написана функция sum2

Тогда, я считаю, багов не существует в природе. Можешь привести пример бага?
Делай что должно, и будь что будет
Re[18]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 13:23
Оценка: +1
Здравствуйте, dotneter, Вы писали:

SH>>Это не баг. Это была нужна функция x — y. Потребуется другая -- будет написана sum2.


D>sum x:int y:int — хочется Х (Х — спецификация оператора +)

D>получилась реализация
D>sum x:int y:int = x — y
D>Это баг

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

Теперь ты говоришь, что подразумевал вот такой вот эталон. Ладно.

Но ведь программист в здравом уме и трезвой памяти написал код x — y. Компьютер понял его буквально и так и выполнил. Потом программист спохватился и понял, что надо x+y.

Чем это отличается от того, что ты, в здравом уме и трезвой памяти напишешь

sum x:int y:int — хочется Х (Х — спецификация оператора +)


И формально докажешь даже. Или формально преобразуешь в код.

А потом спохватишься и поймёшь, что нужно

sum x:int y:int — хочется Х (Х — спецификация оператора -)


Это баг или не баг? Если нет, то почему? Чем одно от другого отличается?
Если да -- то ведь доказали же только что. Значит не совсем то доказали.
Делай что должно, и будь что будет
Re[19]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 13:53
Оценка: -1
Здравствуйте, SergH, Вы писали:

SH>Баг это разница между эталоном и реализацией. Я попросил пример бага, ты привел только реализацию, я сказал что это не баг.

Я надеялся что мы еще в контексте предыдущего примера.


SH>Это баг или не баг? Если нет, то почему? Чем одно от другого отличается?

SH>Если да -- то ведь доказали же только что. Значит не совсем то доказали.

Это баг спецификации а не реализации.
Talk is cheap. Show me the code.
Re[4]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 14:04
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

WH>Эту кракозябру можно написать немного короче:

WH>
WH>zip : forall{A B n} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
WH>

WH>теперь напишем тело этой кракозябры
WH>
WH>zip []    []    = []
WH>zip x::xs y::ys = (x, y) :: zip xs ys
WH>

WH>Все. По другому хрен напишешь ибо компилятор надает по рукам.

Проблема в том, что описание получилось в несколько раз сложнее самой функции.

WH>Также уже доказано что другие варианты обрабатывать не надо. Они просто не пройдут проверку типов.


ОК. А что мы контролировали? И нельзя ли выразить это более просто?

WH>Теперь как это будет выглядеть на немерле

WH>
WH>zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
WH>

WH>Различия только в том что в случае с зависимыми типами указана длинна списков.

Я бы так не сказал. В немероловм варианте есть простор для фантазии (так как реализация не приведена).

Списки могут различаться по длине и при этом реализация может реагировать по разному:
1. Выдать исключение.
2. Отбросить "лишние" элементы из более длинного списка.

По жизни второй вариант будет более востребован, хотя потребоваться могут оба.

Код который нужно добавить, чтобы получить п. 1. не сложен:
zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
  requires l1.Lenght == l2.Lenght
  ensures  value.Lenght == l1.Lenght

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

Как эти проблемы решаются в Агде?

WH>
WH>{
WH>| ([],    [])    => []
WH>| (x::xs, y::ys) => (x, y) :: zip(xs, ys)
WH>| _              => throw InvalidArgumentException()
WH>}
WH>

WH>те в результате мы и написали больше и переложили проверку с компилятора на рантайм.

Я повторюсь, но мне не понятно, как компилятор сможет проверить работу со списками большая часть которых получается динамически?

Или мы будем работать отдельно с динамическими списками (и при этом все проверки пойдут на смарку), и отдельно со статическими?

WH>И после этого ты говоришь что зависимые типы сложнее?


Я пока ничего не говорю. Я просто констатирую факт, что то что ты привел — это весьма туманно, сложно и при этом не понятно решает ли исходные задачи.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 14:41
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

WH>Только при наличии аннотаций которые более многословны чем зависимые типы и покрывают куда меньше утверждений.


Многословность != непонятность. Сравним два варианта:
zip : {n : Nat} -> {A : Set} -> {B : Set} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n

и
zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
  requires l1.Lenght == l2.Lenght
  ensures  value.Lenght == l1.Lenght


WH>А никто не обольщается. Но отказываться от проверок на этапе компиляции это просто глупо.


Не спорю. Но проверки не должны вносить неоправданную сложность. Они должны быть понятным простым смертным.

WH>И вообще эта твоя реплика очень сильно смахивает на отмазки любителей динамической типизации... типа "У нас и так все работает! Нахрена нам статические проверки!?"


Мало ли что на что смахивает? Меня вряд ли можно заподозрить в любви к динамике. Но и любить чистую науку мне как-то тоже не охота. Меня интересует практика. А практика — это всегда компромисс.

VD>>Основной причиной появления багов является сложность задачи. И если система которая должна уберечь от багов будет увеличивать эту самую сложность, то на практике будет ровно противоположенный ожидаемому результат.

WH>А она увеличивает?

Приведенный тобой пример описания типа функции в двое длиннее тела функции и в 10 раз не понятнее (на мой взгляд).

WH>А если вспомнить про то что такая система типов еще и кучу тестов делает бессмысленными?


Кучу ли? Что у нас с динамическими списками? Что у нас с вводом / выводом?
Что, наконец с логикой? Как в систему типов загнать информацию о поведении не тривиального кода?

VD>>Ну, а то что мы тут увидели вряд ли можно назвать простым.

VD>>В прочем, возможно я "не догоняю".
WH>Я таки думаю что не догоняешь.
WH>Ибо зависимые типы по началу выносят мозг покруче чем функциональщина императивщику...

Я не заметил чего-то выносящего мозг. Видимо по второму разу данная трава уже не так выносит .
Я заметил "много букв" при не вполне понятном результате.

В общем, здесь
Автор: VladD2
Дата: 03.07.09
я задал несколько вопросов. Ответь на них. Может это прояснит кое-что.

Я не догматик и умею менять свое мнение. Пока что оно умеренно скептическое. В прочем, скепсис скорее относится к синтаксису и возможностям, а не к самой идее.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 15:01
Оценка: +1
Здравствуйте, dotneter, Вы писали:

SH>>Для доказательства нужно формально сравнить "что хотелось" и "что получилось". Проблема в том, что "что хотелось" в формальном виде отсутствует.

D>sum x:int y:int — хочется Х (Х — спецификация оператора +)
D>получилась реализация
D>sum x:int y:int = x + y
D>которая эквивалентна операции + которая по определению является правильной, следовательно sum удовлетворяет тому что хотелось и является правильной.

Это называется определение через себя. Стандартная логическая ошибка. Самоопределение конечно всегда верно, но при этом совершенно бессмысленно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 04.07.09 08:47
Оценка: +1
Здравствуйте, thesz, Вы писали:

T>Делаем проверку на равенство. Если равны, то можно zip. Не равны, отрежем кого. Или приклеим кому.

Непонимать. Еще раз
listA = getListA (void -> Vec A n) //читает список из файла listA.txt
listB = getListB (void -> Vec B n) //читает список из файла listB.txt

zip listA listB // как тут компилятор понимает какой длинны listA и listB

(Вместо чтения из файла может быть все что угодно)

Делаем равное количетсво записей в listA.txt и listB.txt программа копилируется,
меняем на не равное, не компилируется, так?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 04.07.09 10:11
Оценка: +1
Здравствуйте, dotneter, Вы писали:

D>Наверное имелось в виду

D>
D>listA = getListA (void -> Vec A n)
D>listB = getListB (void -> Vec B n)

D>zip listA listB // как тут компилятор понимает какой длинны listA и listB
D>

Если имеется в виду чтение данных из внешнего источника то нам нужно будет по любому проверить что мы прочитали.
Ибо внешние источники всегда ненадежны.
И тут зависимые типы напомнят нам где нужно вставить проверки.
В данном случае компилятор заставит нас явно проверить что списки одной длинны.
Если использовать более кучерявые типы то компилятор заставит нас сделать проверки еще и других свойств.

Короче как ни крутись, а проверка ввода нужна всегда.

А вот после того как ввод проверен уже никакие проверки не нужны.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 04.07.09 10:33
Оценка: +1
Здравствуйте, Alexey Romanov, Вы писали:

AR>Если имеется ввиду, что getListA имеет тип IO (Vec A n), то это сокращённая запись для {forall A n}(IO (Vec A n)), то есть getListA обещает вернуть список любой длины и любого типа, который нужен. Естественно, чтение из файла такого типа иметь не будет. А будет оно иметь тип

AR>
AR>IO {exists n}(Vec A n)
AR>IO {exists n}(Vec B n)
AR>

AR>То есть возвращается список некоторой натуральной длины. Естественно, эти n могут быть разными.

AR>Но нам ничто не мешает написать функцию

AR>
AR>zip' : (Vec A n) -> (Vec B m) -> (Vec (A,B) (min n m))
AR>

AR>которая соответствует второму варианту VladD2.
Нам то ничего не мешает написать все что угодно, но поинт то был в том что бы zip принимал только списки одинаковой длинны и ругался при компиляции если это не так.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.07.09 18:09
Оценка: +1
Здравствуйте, WolfHound, Вы писали:

VD>>А вот со статической проверкой будут проблемы, так как списки могут формироваться динамически, и их длинна, в общем случае, не известна во время компиляции.

WH>Прелесть зависимых типов в том что они прекрасно работают в данном случае...

Делов в том, что подобные ответы не имеют практического смысла. Это не более чем сотрясение воздуха. Понимания у окружающих, да и твоей правоты это не прибавляет.

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

VD>>Я повторюсь, но мне не понятно, как компилятор сможет проверить работу со списками большая часть которых получается динамически?

VD>>Или мы будем работать отдельно с динамическими списками (и при этом все проверки пойдут на смарку), и отдельно со статическими?
WH>Ты точно не понял что к чему.

Ну, так поясни, а не декларируй никому не интересные вещи о моем понимании.

WH>Непривычно? Да.

WH>Сложно? Нет.

Сложно. Много шума. Это видно очень отчетливо. Возможно все тоже самое можно было бы записать в несколько раз проще. Но в таком виде функцию по сложнее уже будут воспринимать далеко не все.

WH>Решает.


Пока что видны только декларации. Ты так и не рассказал как будет осуществляться контроль времени компиляции, если в функцию передать аргументы полученные динамически.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 21:00
Оценка: +1
Здравствуйте, thesz, Вы писали:

D>>Наверное имелось в виду

D>>
D>>listA = getListA (void -> Vec A n)
D>>listB = getListB (void -> Vec B n)

D>>zip listA listB // как тут компилятор понимает какой длинны listA и listB
D>>


T>Делаем проверку на равенство. Если равны, то можно zip. Не равны, отрежем кого. Или приклеим кому.


То есть верифицировать весь код и заставлять писать все проверки?

А не офигеш ли это делать?

Исключения придумали для того, чтобы когда пишешь логику по меньше думать о редких граничных условиях. Если проверять все, то код может разбухнуть очень и очень сильно.

Кто-нибудь проводил сравнение трудозатрат вызванных тестированием и вызванных тотальными проверками всех нюансов?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 21:17
Оценка: +1
Здравствуйте, VoidEx, Вы писали:

VE>Нет, мы упрощаем код, вводя проверку всего один раз на самом верху (ну или в нужном, но одном месте).

VE>В обычном случае нам приходится постоянно проверять на null, либо знать, что может вылететь NPE (это фактически встроенная та самая дополнительная функция с проверкой, которую ты упомянул), а тут проверку заставляет сделать компилятор, но всего один раз, а дальше мы уже знаем, что ссылка not null.
VE>Это как пример.

Я уверен, что зависимые типы ничем не могут помочь с NRE. Более того эта проблема легко решается (и, кстати сказать, отсуствует в ОКамле и Хаскеле) самой системой типов. Достаточно описать допускающие null типы и не допускающие, а так же описать возможность явного и/или не явного преобразования между ними. Далее для переменных не допускающих null типов компилятор должен требовать инициализацию.

Кстати, на мой взгляд проблема NRE создает куда больше проблем на практике. Вот ее бы решить в мэйнстриме!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 21:34
Оценка: +1
Здравствуйте, lomeo, Вы писали:

L>Вернёмся к рассматриваемому примеру — ты описал на контрактах функцию склеивающую два списка одной длины. И посмотри, что ты будешь делать с ней, когда списки получены динамически, может так тебе будет проще взглянуть на тот же пример со стороны ЗТ.


Дык там есть множество нюансов. Иногда проще забить на проверки времени компиляции и воспользоваться проверками времени выполнения.
Ведь нам нужно чтобы код работал верно, но при этом мы не тратили много времени на вещи не связанные с основной задачей.

L>>>Тут ещё не раз не показали как это можно сделать. А то, что зависимые типы сокращают и упрощают код было уже показано несколько раз.

VD>>Где это было показан?

L>Ну как же, одной строчкой заменяем кучу юнит тестов — сокращение. Простой и явной декларацией в типах заменяем мутные контракты, описывающие ограничения реализации — упрощение.


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

Без специального исследования утверждать, что кода получится меньше я бы не стал. В общем, это весьма голословное утверждение.

Что до надежности, то припоны которые начнет чинить компилятор (а программист именно так это будет воспринимать) начнут обходиться разными путями. Так что ошибки никуда не денутся. Да и ошибки бывают логичекими. Ну, не верный алгоритм. И что тут компилятор скажет? Он же не знает как надо? Для него верен тот алгоритм который может скомпилироваться.

L>Я что хочу сказать — нам не должно быть дело до того, чтобы написаное нами воспринималось всеми. Инструмент должен быть полезен, удобен, понятен в работе в первую очередь тому, кто будет писать и поддерживать код.


В первую очередь должна быть польза. Польза обществу. Если человек будет считать, что инструмент куль и круть, а на деле он начнет писать программы в 10 раз медленнее, то всем будет по фигу, что нужно вам. Всем будет очевидно, что от этого инструмента больше вреда нежели пользы, а те кто им занимаются просто заигрались в игрушки.

VD>>Хиндли-Милнера? Вы меня извините, но в этой системе типов нет ничего выдающегося. В чистом виде она не удобна и весьма убога. А зависимые типы по идее могут применяться с любой системой типов.


L>Возможно. Я не очень близко знаком с зависимыми типами, для меня это лямбда-P из лямбда-куба. Т.е. её применение я пока вижу только в чистых системах типов (PTS).


Я вижу, что зависимые типы спокойно прокатят и в номинальной системе типов с подтипами а-ля С++/Ява/дотнет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 22:08
Оценка: +1
Здравствуйте, lomeo, Вы писали:

Грохнул весь ответ (много букв), так как важна только последняя мысль...

L>Ну и разумеется, почему это ЗТ должны заниматься тотальными проверками всех нюансов, а тестирование не всех? После этого просто нечестно сравнивать трудозатраты.


Да потому, что туча проверок по жизни не нужно. Потому, что программа спокойно может работать "недописанной". Я могу написать алгоритм для обычных условий, а проблемы отловят контракты. Что-то во время компиляции, что-то в рантайме. И меня это в большинстве случаев устроит.

Более того. Ну, представим компилятор заставил меня обрабатывать какие-то несоответствия. ОК. А как я их обработаю? Ну, не сошлась у меня длинна двух списков перед вызовом zip-а. И что мне делать? Исключения кидать? Дык, а зачем я тогда пишу код проверок? Пусть его кидает сам zip.
Писать какой-то код реакции? Дык это может резко увеличить объем работы и при этом один хрен многие схалтурят и напишут какую-нибудь ересь.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 22:18
Оценка: :)
Здравствуйте, VladD2, Вы писали:

L>>Так система типов — это та же лямбда! Почему бы над ней и не попроводить вычисления?

VD>Потому, что результат печальный выходит. В коде могут разобраться 1-2 процента программистов, а остальные тихо ...
VD>Для МП должны быть явные и простые средства. Система же типов должна уменьшать количество ошибок и предоставлять метаиформацию (рефлексия, интелисенс в IDE и т.п.).

Система типов должна описывать ограничения. Ограничения очень хорошо описываются выражениями, над выражениями обычно производятся вычисления.

Что касается 1-2 процентов программистов — почему тебя это так волнует? Ты же себе инструмент должен подобрать, а не 98-99% программистов.

L>>Единственное отличие — язык системы типов должен быть тотальным.

VD>Переведи.

Не должен обладать Тьюринг-полнотой. Должен завершаться.
Re[15]: [Зависимые типы] Объясните на пальцах.
От: Alexey Romanov  
Дата: 08.07.09 09:19
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, lomeo, Вы писали:


L>>Система типов должна описывать ограничения. Ограничения очень хорошо описываются выражениями, над выражениями обычно производятся вычисления.


VD>С этим я согласен. Но, я о другом говорю, о том, что вычисления над типами не должны приводить к другим эффектам. К генерации кода как в шаблонах С++. Или к посылке мыла на почтовый ящик.


То есть язык для типов должен быть чисто функциональный А чтобы переменные не меняли тип по ходу выполнения программы -- изменяемых объектов быть вообще не должно.
Re[13]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 13.07.09 03:24
Оценка: +1
Здравствуйте, thesz, Вы писали:

T>Оптимизатор так себе, поскольку толком не отработан, сами реализации тоже пишет всего один человек, а уже всего вдвое хуже C.


А причем тут оптимизатор?
Я сравнивал только размер исходников. И при этом высокуровневый ATS продул Си.

Насчет оптимизатора, он просто попытался повторить "подвиг" автора языка D который несколько лет назад тоже ваяя язык в одиночку и вообще умудрился занять весь топ на http://shootout.alioth.debian.org/ это совершенно ничего ни говорит о быстродействии языка, это говорит только о том что можно легко подогнать язык под тесты.
Re[20]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 21.07.09 14:50
Оценка: +1
Здравствуйте, FR, Вы писали:

FR>Мне интересна цена в выразительности которую надо платить за зависимые типы. Поэтому

FR>все кроме объема исходников меня в этих тестах не интерсует, и по этому параметру
FR>ATS конкретно сливает.

Согласен. Но нет четкого доказательства, что сливает они из-за применения зависимых типов, а не почему-то еще (например, из-за кривого синтаксиса или выбора более быстрого, но более пухлого алгоритма).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[24]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 21.07.09 20:39
Оценка: :)
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, thesz, Вы писали:


T>>Тем же концом и тебя.


FR>


T>>>>Так вот, возьми и напиши что-либо реальное на обычном ЯП и на ЯП с зависимыми типами. Чего на шутаут кивать, который — о, ужас! — знаменит подгонками?

FR>>>ATS меня заинтересовал, но времени совсем нет
FR>>>Так что жду хоть небольших примеров от евангилистов

T>>Сам разберёшься. Не много-то и надо.


FR>Что-то в последнее время евангилисты жидкие пошли, немерлисты не ленились простыни кода выкатывали


Как и я в своё время.

Сейчас я немного занят.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[3]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 17.08.09 20:17
Оценка: :)
Здравствуйте, chukichuki, Вы писали:

C>Как я понимаю, код обработки нештатных ситуаций никуда не девается. Просто в случае его отсутствия программа не скомпилируется.

Он как минимум исчезает из собственно функции Zip.
Клиенты функции Zip могут также от него избавиться.

C>Например, прежде чем передавать произвольные списки a : Vec A n и b : Vec B m на вход нашему zip-у, необходимо чтобы компилятор увидел код в котором мы проверяем что для а и b справедливо n = m.

Если эти списки читаются из внешних источников то такой код необходим.
Ибо при чтении данных из внешних источников мы вообще ничего не можем гарантировать по этому все приходится проверять.

Если же мы говорим про списки внутри программы то у меня есть чувство что в подавляющем большинстве случаев (а может и вообще всегда) можно доказать что списки одинаковой длинны без проверок времени исполнения.

C>В противном случае система вывода типов не даст скомпилировать программу. Поэтому код проверки строго говоря никуда не девается. Он остается. Просто само количество проверок может несколько оптимизироваться.

Все проверки выдавливаются на уровень получения данных из внешних источников.
А внутри программы мы уже сидим на статических доказательствах.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[11]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.09 21:56
Оценка: +1
Здравствуйте, VoidEx, Вы писали:

VD>>Ерунду какую-то говоришь. Проверка типов есть в любом языке не зависимо от наличия в нем вывода типов.


VE>Именно, поэтому переписываю код WolfHound'а на Си++

VE>
VE>template <class A, class B, unsigned int n>
VE>Vec<B, n> vmap(std::function<B (A)> f, Vec<A, n> const &)
VE>{ ... }
VE>

VE>Где тут вывод типов?

Где-то в недрах "...". Точнее, так как это шаблон, то его вообще нет. Набор токенов, есть набор токенов. Вывод типов начнется когда в шаблон раскроется и в "..." попадут реальные типы.

А вообще, в твоем ответе чувствуется что-то не адекватное. Или ты не понял о чем идет речь, или намеренно пытаешься превратить обсуждение в бессмысленную кашу.

VE>Вот если бы сигнатуры vmap не было, то был бы вывод. А при подстановке конкретных параметров — это уже type check, как правильно заметил lomeo


Прочти еще раз ветку со слов Вольфхаунда и ниже. Обрати внимание, на слова о выводе типов внутри тел методов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
[Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 01.07.09 16:23
Оценка:
Кто нибудь может в пяти строчках кода и паре предложений выразить суть и основные бенефиты идеи?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[2]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 01.07.09 18:46
Оценка:
Здравствуйте, WolfHound, Вы писали:

Тоесть, можно сказать что это есть контракты на уровне типов? Только как компилятор узнает
>значения времени исполнения
тривиальные случаи еще можно понять, но я так думаю ими дело не обходится?
Значительно ли это выигрывает какой нибудь анализ кода навроде контрактов в net 4.0?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[3]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 01.07.09 19:47
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

WH>>Теперь если компилятор не будет уверен что в эту функцию передают списки одинаковой длинны то программа не скомпилируется.

BZ>... и процесс написания программы выглядит как сдача экзамена
И хорошо. Пусть у компилятора бошка болит на тему где еще соломку не подстелили.

BZ>компилятор: а это вы откуда вывели?

BZ>юзер: ну вот, если эпсилон равен гамме, то Юпитер в фазе Венеры..
BZ>компилятор: докажи!
И докажу. Особенно если мы говорим о практической реализации идеи, а не очередной исследовательской работе.
А если лень, трудно или невозможно что-то доказать всегда можно попросить компилятор сгенерировать проверку времени исполнения.
Например:
lameZip : {n m : Nat}{A B : Set} -> (v1 : Vec A n) -> (v2 : Vec B m) -> Vec (A, B) n
lameZip = zip v1 (v2 :> Vec B n)

Собственно привидение Vec B m к Vec B n вставляет проверку что n == m, а если нет то вылетает исключение.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 01.07.09 20:15
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Тоесть, можно сказать что это есть контракты на уровне типов?

Что-то типа того.

D>Только как компилятор узнает

>>значения времени исполнения
А ему не нужно их узнавать

D>тривиальные случаи еще можно понять, но я так думаю ими дело не обходится?

Не обходится.

D>Значительно ли это выигрывает какой нибудь анализ кода навроде контрактов в net 4.0?

Судя по той инфе что я нашол по контрактам в .NET4 думаю значительно.

Можешь начинать читать отсюда: http://wiki.portal.chalmers.se/agda/agda.php
Предупреждаю с непривычки выносит мозг. Но вынос мозга штука полезная...
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[3]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 01.07.09 20:21
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, WolfHound, Вы писали:


D>Тоесть, можно сказать что это есть контракты на уровне типов? Только как компилятор узнает

>>значения времени исполнения
D>тривиальные случаи еще можно понять, но я так думаю ими дело не обходится?

Создание XML, который не может нарушить заданную схему.

Гарантированно правильные интерпретаторы.

Строго типизированная рефлексия.

D>Значительно ли это выигрывает какой нибудь анализ кода навроде контрактов в net 4.0?


Для зависимых типов не нужен запуск программы. Для контрактов нужен.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[4]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 01.07.09 20:41
Оценка:
Здравствуйте, thesz, Вы писали:

T>Для зависимых типов не нужен запуск программы. Для контрактов нужен.

У контрактов проверка может быть не только в рантайме.
Например
def test(x):
    requires(x > 0)

test(-10)

Выдаст предупреждение не запуская программу.
Но на этом строго типизированую рефлексию не построишь. Мне вообще сложно представить как это возможно ведь то что мы рефлексируем может быть чем угодно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[2]: [Зависимые типы] Объясните на пальцах.
От: kmmbvnr Россия http://kmmbvnr.livejournal.com
Дата: 02.07.09 00:55
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, dotneter, Вы писали:


WH>
WH>data Vec (A : Set) : Nat -> Set where
WH>  [] : Vec A zero
WH>  _::_ : {n : Nat} -> A -> Vec A n -> Vec A (suc n)
WH>

WH>В данном случае описывается список тип которого параметризован не только типом элементов содержащихся в списке но и длинной этого списка.
WH>Первый конструктор создает пустой список с типом которого связано значение 0.
WH>Второй конструктор интереснее.
WH>Первый (неявный) аргумент это длинна исходного списка.
WH>Второй элемент.
WH>Третий исходный список с типом которого связанна длинна.
WH>И с результатом связанна длинна исходного списка плюс один.

Мне кажеться или это чем-то похоже на

template <int v>
struct Int2Type
{
   enum { value = v; }
}


?
-- Главное про деструктор копирования не забыть --
Re[3]: [Зависимые типы] Объясните на пальцах.
От: VoidEx  
Дата: 02.07.09 03:00
Оценка:
Здравствуйте, kmmbvnr, Вы писали:

K>Мне кажеться или это чем-то похоже на


K>?


Кажется.
Re: [Зависимые типы] Объясните на пальцах.
От: Mazay Россия  
Дата: 02.07.09 04:12
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Кто нибудь может в пяти строчках кода и паре предложений выразить суть и основные бенефиты идеи?

Вот здесь коннечно не в паре предложений, но суть понятна.
Еще много чего по теме можно найти по ссылкам вот отсюда
Главное гармония ...
Re[5]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 02.07.09 11:19
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, thesz, Вы писали:


T>>Для зависимых типов не нужен запуск программы. Для контрактов нужен.

D>У контрактов проверка может быть не только в рантайме.
D>Например
D>
D>def test(x):
D>    requires(x > 0)

D>test(-10)
D>

D>Выдаст предупреждение не запуская программу.

Проверка зависимых типов ведётся на этапе компиляции. Проверка некоторых контрактов ведётся на этапе компиляции.

Поэтому для некоторых контрактов не нужен запуск программы, а в общем случае нужен.

D>Но на этом строго типизированую рефлексию не построишь. Мне вообще сложно представить как это возможно ведь то что мы рефлексируем может быть чем угодно.


Типы имеют определённую структуру. Например, алгебраические типы могут быть представлены, как сумма произведений с оператором фиксированной точки.

На это можно смотреть, это можно преобразовывать.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[3]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 02.07.09 21:17
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Вопрос только в одном, на сколько это сложнее обычоного подхода. Судя по приведенной кракозябре, намного.

А что это за обычный подход который рубит половину багов на этапе компиляции?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[3]: [Зависимые типы] Объясните на пальцах.
От: Аноним  
Дата: 03.07.09 05:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, WolfHound, Вы писали:


WH>>
WH>>zip : {n : Nat} -> {A : Set} -> {B : Set} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
WH>>


WH>>Как следствие если не лениться писать правильные типы то можно избавиться не только от кучи проверок в функции на тему, а не подсунули ли нам какую гадость и что делать если таки подсунули, но и юнит/интеграционных тестов ибо система типов их перекрывает с большим запасом.


VD>Вопрос только в одном, на сколько это сложнее обычоного подхода. Судя по приведенной кракозябре, намного.


Это если считать обычным подходом код без модульных тестов и без проверок параметров функции. Если первое неплохо автоматизируется с помощью того же PEX (сам пока не пользовался, но допустим), то от второго, вроде как, никуда не денешься. Хотя, на первый взгляд, да, действительно громоздко.

Во всяком случае, без дополнительного изучения, так однозначно отвергать эту штуку не стоит, или за твоими словами кроется некий опыт использования/изучения этого подхода? В таком случае, было бы очень интересно услышать подробности.
Re[5]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 08:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Статическая верификация кода возможна и так.

Имхо, основной вопрос в том насколько сложно реализовывать верификаторы, и насколько сложные задачи они могут решать.
Конечно если у нас есть мега интеллектуальная система которая выявляет любые ошибки, то нам не только не нужна мощная система типов, нам и сами типы нужны.

VD>Что до багов, то они никуда не исчезнут. В этом вопросе нет волшебной палочки.

Так я написал, что половину.
Talk is cheap. Show me the code.
Re[5]: [Зависимые типы] Объясните на пальцах.
От: BulatZiganshin  
Дата: 03.07.09 09:07
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Что до багов, то они никуда не исчезнут. В этом вопросе нет волшебной палочки. Баги сазажают люди. Если алгоритм крив, то никакая верификция или мощная система типов не спасет. Не надо обольщаться.


ты можешь *доказать*, что некая программа не содержит багов?
Люди, я люблю вас! Будьте бдительны!!!
Re[6]: [Зависимые типы] Объясните на пальцах.
От: Аноним  
Дата: 03.07.09 09:34
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>Здравствуйте, VladD2, Вы писали:


VD>>Что до багов, то они никуда не исчезнут. В этом вопросе нет волшебной палочки. Баги сазажают люди. Если алгоритм крив, то никакая верификция или мощная система типов не спасет. Не надо обольщаться.


BZ>ты можешь *доказать*, что некая программа не содержит багов?


В общем случае этого никто не может. Кстати, доказательства (особенно достаточно сложные) также могут содержать ошибки, так что даже наличие доказательства безошибочности программы отнюдь не гарантирует отсутсвие ошибок в этой программе.

Кроме того интересует насколько дорого обходится повышение качества программы посредством использования доказательств. Скажем, рассмотрим такой пример (все цифры взяты с потолка). Мы создаём некоторое ПО (не для управления ядерным реактором). Используя привычные средства повышения качества (модульные тесты, ревью кода) имеем 10 ошибок на 1000 строк кода (взято с потолка) и затрачиваем на это X ресурсов. Если мы воспользуемся зависимыми типами докажем, что у нас 0 ошибок на 1000 строк кода, но потратим на это 2X ресурсов, то зачем нам это доказательство?. ИМХО, гораздо интереснее узнать, как именно влияют зависимые типы на качество и стоимость ПО, нежели абстрактная возможность "доказать" отсутвие ошибок для некоторых программ.
Re[3]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 03.07.09 09:40
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Вопрос только в одном, на сколько это сложнее обычоного подхода. Судя по приведенной кракозябре, намного.

Эту кракозябру можно написать немного короче:
zip : forall{A B n} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n

теперь напишем тело этой кракозябры
zip []    []    = []
zip x::xs y::ys = (x, y) :: zip xs ys

Все. По другому хрен напишешь ибо компилятор надает по рукам.
Также уже доказано что другие варианты обрабатывать не надо. Они просто не пройдут проверку типов.

Теперь как это будет выглядеть на немерле
zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]

Различия только в том что в случае с зависимыми типами указана длинна списков.

{
| ([],    [])    => []
| (x::xs, y::ys) => (x, y) :: zip(xs, ys)
| _              => throw InvalidArgumentException()
}

те в результате мы и написали больше и переложили проверку с компилятора на рантайм.

И после этого ты говоришь что зависимые типы сложнее?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 03.07.09 09:45
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>ты можешь *доказать*, что некая программа не содержит багов?

Доказать можно только формальные утверждения.
Утверждение "программа не содержит багов" не формализуемо. Те доказано быть не может.
Но мы можем доказать соответствие спецификации, а это уже очень и очень не мало.
В любом случае зависимые типы убивают кучу тестов. Остаются только функциональные на случай если в спецификации написано не то что должно быть там написано.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 03.07.09 09:54
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Статическая верификация кода возможна и так. Вон в 4-ом фрэйворке вроде как будет поддерживаться для реальных систем.

Только при наличии аннотаций которые более многословны чем зависимые типы и покрывают куда меньше утверждений.

VD>Что до багов, то они никуда не исчезнут. В этом вопросе нет волшебной палочки. Баги сазажают люди. Если алгоритм крив, то никакая верификция или мощная система типов не спасет. Не надо обольщаться.

А никто не обольщается. Но отказываться от проверок на этапе компиляции это просто глупо.
И вообще эта твоя реплика очень сильно смахивает на отмазки любителей динамической типизации... типа "У нас и так все работает! Нахрена нам статические проверки!?"

VD>Основной причиной появления багов является сложность задачи. И если система которая должна уберечь от багов будет увеличивать эту самую сложность, то на практике будет ровно противоположенный ожидаемому результат.

А она увеличивает?
А если вспомнить про то что такая система типов еще и кучу тестов делает бессмысленными?

VD>Ну, а то что мы тут увидели вряд ли можно назвать простым.

VD>В прочем, возможно я "не догоняю".
Я таки думаю что не догоняешь.
Ибо зависимые типы по началу выносят мозг покруче чем функциональщина императивщику...
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: [Зависимые типы] Объясните на пальцах.
От: deniok Россия  
Дата: 03.07.09 10:05
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Баг это отличие программы от спецификации. Или отличие спецификации от "того, что имелось ввиду". Имея на руках только программу ни то ни другое доказать невозможно. Если есть формальная спецификация, по которой можно что-то доказывать, то скорее всего её можно формально и преобразовать в программу, т.е. "формальная спецификация" это программа и есть. Осталась только разница между спецификацией и мечтой, и вот она видимо неустранима и соответствие не доказать.


Мечта — это чтобы программы сами писались?
Зависимые типы позволяют довольно удобно записывать широкий класс спецификаций. Например, отсортированный список на Агде можно описать так:
data OList : Nat -> Set where 
  Nil  : {b : Nat} -> OList b 
  Cons : {b : Nat} -> (x : Nat) -> (b ≤ x) -> OList x -> OList b

Теперь функция с типом
sort : List Nat -> OList 0

либо не компилируется, либо гарантированно возвращает отсортированное.
Re[8]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 10:18
Оценка:
Здравствуйте, deniok, Вы писали:

D>Мечта — это чтобы программы сами писались?


Мечта это "то, что имелось ввиду".

D>Зависимые типы позволяют довольно удобно записывать широкий класс спецификаций. ...


Не, не, я понимаю, что это ещё один ещё более высокоуровневый язык и это наверное хорошо, если в этом разобраться.
Я только про то, что "доказать, что нет багов" невозможно концептуально, вне зависимости от языков, средств и т.п.
Делай что должно, и будь что будет
Re[9]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 10:44
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Я только про то, что "доказать, что нет багов" невозможно концептуально, вне зависимости от языков, средств и т.п.

Даже для
sum x y = x + y

?
Talk is cheap. Show me the code.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 03.07.09 10:53
Оценка:
Здравствуйте, dotneter, Вы писали:

SH>>Я только про то, что "доказать, что нет багов" невозможно концептуально, вне зависимости от языков, средств и т.п.

D>Даже для
http://rsdn.ru/forum/decl/3454285.1.aspx
Автор: WolfHound
Дата: 03.07.09
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 11:02
Оценка:
Здравствуйте, thesz, Вы писали:

T>Для зависимых типов не нужен запуск программы. Для контрактов нужен.


Неправда.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 11:24
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, BulatZiganshin, Вы писали:


BZ>>Здравствуйте, VladD2, Вы писали:


VD>>>Что до багов, то они никуда не исчезнут. В этом вопросе нет волшебной палочки. Баги сазажают люди. Если алгоритм крив, то никакая верификция или мощная система типов не спасет. Не надо обольщаться.


BZ>>ты можешь *доказать*, что некая программа не содержит багов?


А>В общем случае этого никто не может. Кстати, доказательства (особенно достаточно сложные) также могут содержать ошибки, так что даже наличие доказательства безошибочности программы отнюдь не гарантирует отсутсвие ошибок в этой программе.

В данном случае доказывает компьютер, а он не ошибается.

А>Кроме того интересует насколько дорого обходится повышение качества программы посредством использования доказательств. Скажем, рассмотрим такой пример (все цифры взяты с потолка). Мы создаём некоторое ПО (не для управления ядерным реактором). Используя привычные средства повышения качества (модульные тесты, ревью кода) имеем 10 ошибок на 1000 строк кода (взято с потолка) и затрачиваем на это X ресурсов. Если мы воспользуемся зависимыми типами докажем, что у нас 0 ошибок на 1000 строк кода, но потратим на это 2X ресурсов, то зачем нам это доказательство?. ИМХО, гораздо интереснее узнать, как именно влияют зависимые типы на качество и стоимость ПО, нежели абстрактная возможность "доказать" отсутвие ошибок для некоторых программ.


Ты рассматриваеш ситуацию полярно — либо "стандартные" средства, либо статические проверки.
На самом деле несть континуум промежуточных "состояний".

Сначала ты пользуешься элементарными типами для проверки правильности кода — возвращает ли метод строку или число (катсти в динамических языках даже такие мелочи надо тестировать), потом используешь более сложные конструкции, которые тебе позволяют ограничить множества входных и выходных значений для элементарных типов. Далее, если позволяет язык, уже используются типы, которые описывают некоторые свойства сложных объектов, на каждом этапе сложность описываемых объектов возрастает.
Компилятор естественно статически проверяет, что в процессе работы программы эти свойства нарушены не будут. Все эти проверки снижают количество необходимых тестов.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: Аноним  
Дата: 03.07.09 11:26
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, SergH, Вы писали:


SH>>Я только про то, что "доказать, что нет багов" невозможно концептуально, вне зависимости от языков, средств и т.п.

D>Даже для
D>
D>sum x y = x + y
D>

D>?

А если в спецификации было написано "реализовать функцию вычитания целых чисел с именем sub"?
Re[8]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 11:30
Оценка:
Здравствуйте, deniok, Вы писали:

D>Здравствуйте, SergH, Вы писали:


SH>>Баг это отличие программы от спецификации. Или отличие спецификации от "того, что имелось ввиду". Имея на руках только программу ни то ни другое доказать невозможно. Если есть формальная спецификация, по которой можно что-то доказывать, то скорее всего её можно формально и преобразовать в программу, т.е. "формальная спецификация" это программа и есть. Осталась только разница между спецификацией и мечтой, и вот она видимо неустранима и соответствие не доказать.


D>Мечта — это чтобы программы сами писались?

D>Зависимые типы позволяют довольно удобно записывать широкий класс спецификаций. Например, отсортированный список на Агде можно описать так:
D>
D>data OList : Nat -> Set where 
D>  Nil  : {b : Nat} -> OList b 
D>  Cons : {b : Nat} -> (x : Nat) -> (b ≤ x) -> OList x -> OList b
D>

D>Теперь функция с типом
D>
D>sort : List Nat -> OList 0
D>

D>либо не компилируется, либо гарантированно возвращает отсортированное.

А можно ли потом такой передать как обычный список в другую функцию? Будет неявное реобразование типа? Потребуется ли явное преобразование или может еще какие операции?
Re[11]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 11:43
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Для доказательства нужно формально сравнить "что хотелось" и "что получилось". Проблема в том, что "что хотелось" в формальном виде отсутствует.

sum x:int y:int — хочется Х (Х — спецификация оператора +)
получилась реализация
sum x:int y:int = x + y
которая эквивалентна операции + которая по определению является правильной, следовательно sum удовлетворяет тому что хотелось и является правильной.
Talk is cheap. Show me the code.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 11:59
Оценка:
Здравствуйте, dotneter, Вы писали:

D>sum x:int y:int — хочется Х (Х — спецификация оператора +)


Это ты сейчас думаешь, что тебе этого хочется Это может оказать заблуждением. Вдруг тебе понадобится искусственное переполнение на границе 2^32, для совместимости с С-библиотекой?
Делай что должно, и будь что будет
Re[5]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 12:04
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, thesz, Вы писали:


T>>Для зависимых типов не нужен запуск программы. Для контрактов нужен.


G>Неправда.


http://rsdn.ru/forum/philosophy/3395836.1.aspx
Автор: thesz
Дата: 19.05.09


Проверь контрактом во время компиляции факт правильного упорядочения списка.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[9]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 12:12
Оценка:
D>>Мечта — это чтобы программы сами писались?
D>>Зависимые типы позволяют довольно удобно записывать широкий класс спецификаций. Например, отсортированный список на Агде можно описать так:
D>>
D>>data OList : Nat -> Set where 
D>>  Nil  : {b : Nat} -> OList b 
D>>  Cons : {b : Nat} -> (x : Nat) -> (b ≤ x) -> OList x -> OList b
D>>

D>>Теперь функция с типом
D>>
D>>sort : List Nat -> OList 0
D>>

D>>либо не компилируется, либо гарантированно возвращает отсортированное.

G>А можно ли потом такой передать как обычный список в другую функцию? Будет неявное реобразование типа? Потребуется ли явное преобразование или может еще какие операции?


Список с доказательством имеет структуру, аналогичную обычному списку. Все доказательства изъяты на момент компиляции.

Поэтому, несмотря на "необходимость преобразований", расходы будут нулевыми.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[11]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 12:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А если в спецификации было написано "реализовать функцию вычитания целых чисел с именем sub"?

Не уловил подвох.
Talk is cheap. Show me the code.
Re[13]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 12:18
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Вдруг тебе понадобится ...

Будет написана функция sum2
Talk is cheap. Show me the code.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 12:21
Оценка:
Здравствуйте, thesz, Вы писали:

T>Здравствуйте, gandjustas, Вы писали:


G>>Здравствуйте, thesz, Вы писали:


T>>>Для зависимых типов не нужен запуск программы. Для контрактов нужен.


G>>Неправда.


T>http://rsdn.ru/forum/philosophy/3395836.1.aspx
Автор: thesz
Дата: 19.05.09


T>Проверь контрактом во время компиляции факт правильного упорядочения списка.


Его контрактом даже описать не получится.

А то что получается описывать контрактом проверяется статически.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 12:30
Оценка:
Здравствуйте, thesz, Вы писали:

D>>>Мечта — это чтобы программы сами писались?

D>>>Зависимые типы позволяют довольно удобно записывать широкий класс спецификаций. Например, отсортированный список на Агде можно описать так:
D>>>
D>>>data OList : Nat -> Set where 
D>>>  Nil  : {b : Nat} -> OList b 
D>>>  Cons : {b : Nat} -> (x : Nat) -> (b ≤ x) -> OList x -> OList b
D>>>

D>>>Теперь функция с типом
D>>>
D>>>sort : List Nat -> OList 0
D>>>

D>>>либо не компилируется, либо гарантированно возвращает отсортированное.

G>>А можно ли потом такой передать как обычный список в другую функцию? Будет неявное реобразование типа? Потребуется ли явное преобразование или может еще какие операции?


T>Список с доказательством имеет структуру, аналогичную обычному списку. Все доказательства изъяты на момент компиляции.


T>Поэтому, несмотря на "необходимость преобразований", расходы будут нулевыми.


Это я понимаю.

А в коде как оно выглядеть будет?
Есть например две функции
sort : List Nat -> OList 0
otherFunc : List Nat -> не_важно_что

Можно ли записать композицию sort >> otherFunc (или как оно там пишется) или нужны еще какие-то телодвижения?
Re[15]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 12:33
Оценка:
Здравствуйте, SergH, Вы писали:


SH>Тогда, я считаю, багов не существует в природе. Можешь привести пример бага?

sum x y = x - y
Talk is cheap. Show me the code.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 12:34
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Его контрактом даже описать не получится.


Инварианты класса?
Talk is cheap. Show me the code.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: BulatZiganshin  
Дата: 03.07.09 12:59
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Баг это отличие программы от спецификации. Или отличие спецификации от "того, что имелось ввиду". Имея на руках только программу ни то ни другое доказать невозможно. Если есть формальная спецификация, по которой можно что-то доказывать, то скорее всего её можно формально и преобразовать в программу, т.е. "формальная спецификация" это программа и есть.


вот об этом процессе и идёт речь. в C# или хаскеле он не поддерживается
Люди, я люблю вас! Будьте бдительны!!!
Re[8]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 13:03
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, gandjustas, Вы писали:


G>>Его контрактом даже описать не получится.


D>Инварианты класса?


Это лишь набор утверждений, которые должны выполняться после вызова любого метода.
А с помощью утверждений упорядоченность списка выразить не получится.
Re[17]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 13:06
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Это не баг. Это была нужна функция x — y. Потребуется другая -- будет написана sum2.


sum x:int y:int — хочется Х (Х — спецификация оператора +)
получилась реализация
sum x:int y:int = x — y
Это баг
Talk is cheap. Show me the code.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: Аноним  
Дата: 03.07.09 13:06
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, Аноним, Вы писали:


А>>А если в спецификации было написано "реализовать функцию вычитания целых чисел с именем sub"?

D>Не уловил подвох.

Подвох в том, что глядя даже на такую простую штуку как
sum x y = x + y

нельзя сказать есть в коде бага или нет.
Re[13]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 13:09
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, dotneter, Вы писали:


D>>Здравствуйте, Аноним, Вы писали:


А>>>А если в спецификации было написано "реализовать функцию вычитания целых чисел с именем sub"?

D>>Не уловил подвох.

А>Подвох в том, что глядя даже на такую простую штуку как

А>
А>sum x y = x + y
А>

А>нельзя сказать есть в коде бага или нет.

Можно, если у тебя есть спецификация. А если нет, то вообще непонятно зачем ты код написал.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 13:16
Оценка:
Здравствуйте, dotneter, Вы писали:

VD>>Статическая верификация кода возможна и так.

D>Имхо, основной вопрос в том насколько сложно реализовывать верификаторы, и насколько сложные задачи они могут решать.
D>Конечно если у нас есть мега интеллектуальная система которая выявляет любые ошибки, то нам не только не нужна мощная система типов, нам и сами типы нужны.

Согласен. Основная проблема верификторов в том, что для них требуется дополнительная разметка кода. Скажем чтобы верификатор контролировал недопустимость null-ов в параметрах нам нужно пометить параметры особым образом. А если такая пометка не обязательна, то программист (даже не очень ленивый) с большой вероятностью забьет на это. Причем с null проблема решается введением по умолчанию недопустимости null. А вот с инвариантами и т.п. значительно хуже.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 13:42
Оценка:
T>>>>Для зависимых типов не нужен запуск программы. Для контрактов нужен.
G>>>Неправда.
T>>http://rsdn.ru/forum/philosophy/3395836.1.aspx
Автор: thesz
Дата: 19.05.09

T>>Проверь контрактом во время компиляции факт правильного упорядочения списка.
G>Его контрактом даже описать не получится.

Ну, а в зависимых типах это возможно.

G>А то что получается описывать контрактом проверяется статически.


Перечисли, пожалуйста, что же можно проверить контектом.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[11]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 13:44
Оценка:
T>>Список с доказательством имеет структуру, аналогичную обычному списку. Все доказательства изъяты на момент компиляции.
T>>Поэтому, несмотря на "необходимость преобразований", расходы будут нулевыми.
G>Это я понимаю.
G>А в коде как оно выглядеть будет?
G>Есть например две функции
G>
G>sort : List Nat -> OList 0
G>otherFunc : List Nat -> не_важно_что
G>

G>Можно ли записать композицию sort >> otherFunc (или как оно там пишется) или нужны еще какие-то телодвижения?

Нужны телодвижения.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[16]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 13:48
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, SergH, Вы писали:



SH>>Тогда, я считаю, багов не существует в природе. Можешь привести пример бага?

D>
D>sum x y = x - y
D>


Метрика Минковского — d^2=c^2*t^2-r^2 — это ошибочная запись обычной метрики пространства (d^2=c^2*t^2+r^2).

Зато какие интересные эффекты мы видим из-за этого!..
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[5]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 13:55
Оценка:
VD>К тому же я практически уверен, что юнит-тесты от этого не исчезнут. Юнит-тесты проверяют поведение, а описать поведение статически просто невозможно. Это и есть код.

Боже ж мой.

Код и есть статическое описание поведения.

То есть, мы статически — кодом, ведь код-то не меняется во время исполнения, — описываем поведение программы.

Таким образом, поведение описывается исключительно статическим образом. Даже если это тесты.

Я бы понял, если бы ты сослался на проблему останова, но ты же про неё не знаешь, ведь так?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[14]: [Зависимые типы] Объясните на пальцах.
От: Аноним  
Дата: 03.07.09 14:11
Оценка:
Здравствуйте, gandjustas, Вы писали:

[snip]

G>Можно, если у тебя есть спецификация. А если нет, то вообще непонятно зачем ты код написал.


Да не писал я никакого кода.

SH>>>>>Я только про то, что "доказать, что нет багов" невозможно концептуально, вне зависимости от языков, средств и т.п.
D>>>>Даже для
D>>>>

D>>>>sum x y = x + y
D>>>>

D>>>>?

А>>>А если в спецификации было написано "реализовать функцию вычитания целых чисел с именем sub"?
D>>Не уловил подвох.

А>Подвох в том, что глядя даже на такую простую штуку как
А>
А>sum x y = x + y
А>

А>нельзя сказать есть в коде бага или нет.


Выше история сообщений. В исходном примере (который написал не я) ни о какой спецификации речи нет. Там только вопрос можно-ли доказать отсутсвие багов для такого кода. Как я понял, имелось в виду, что уж в таком простом случае никакой ошибки не может быть в принципе. На это я ответил, что если в спецификации было написано, что нужно реализовать вычитание, то код ошибочный. Собственно, о том и речь, что о правильности кода можно говорить только когда есть и код и спецификация.
Re[8]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 14:14
Оценка:
Здравствуйте, thesz, Вы писали:

T>>>>>Для зависимых типов не нужен запуск программы. Для контрактов нужен.

G>>>>Неправда.
T>>>http://rsdn.ru/forum/philosophy/3395836.1.aspx
Автор: thesz
Дата: 19.05.09

T>>>Проверь контрактом во время компиляции факт правильного упорядочения списка.
G>>Его контрактом даже описать не получится.
T>Ну, а в зависимых типах это возможно.
В .NET кстати есть IOrderedEnumerable, IOrderedQueryable которые как раз обозначают упорядоченную последовательность.
После того поста я начал активно их использовать.

G>>А то что получается описывать контрактом проверяется статически.


T>Перечисли, пожалуйста, что же можно проверить контектом.

Много чего, только не получится расширить существующие типы для обеспечения проверок. Поэтому упорядоченность списка не получится прверить.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 14:15
Оценка:
Здравствуйте, thesz, Вы писали:

T>>>Список с доказательством имеет структуру, аналогичную обычному списку. Все доказательства изъяты на момент компиляции.

T>>>Поэтому, несмотря на "необходимость преобразований", расходы будут нулевыми.
G>>Это я понимаю.
G>>А в коде как оно выглядеть будет?
G>>Есть например две функции
G>>
G>>sort : List Nat -> OList 0
G>>otherFunc : List Nat -> не_важно_что
G>>

G>>Можно ли записать композицию sort >> otherFunc (или как оно там пишется) или нужны еще какие-то телодвижения?

T>Нужны телодвижения.

И как они будут выглядеть?
Re[6]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 14:18
Оценка:
Здравствуйте, thesz, Вы писали:

VD>>К тому же я практически уверен, что юнит-тесты от этого не исчезнут. Юнит-тесты проверяют поведение, а описать поведение статически просто невозможно. Это и есть код.


T>Боже ж мой.

T>Код и есть статическое описание поведения.
T>То есть, мы статически — кодом, ведь код-то не меняется во время исполнения, — описываем поведение программы.
T>Таким образом, поведение описывается исключительно статическим образом. Даже если это тесты.

Ты видимо не понял. Если можно написать спецификацию поведения некоторого объекта, то эта спецификация будет не проще самого кода объекта, вероятнее всего гораздо сложнее. Как потом доказать что спецификация написана без ошибок?
Re[21]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 03.07.09 14:37
Оценка:
Здравствуйте, SergH, Вы писали:

SH>А в чём разница?

В глобальном смысле наверное не в чем. В практическом же, нужно принять уровни которые считаются по определению правильными и на основе чего можно делать выводы о правильности реализации.
sum x y = x + y
Предполагается правильность спецификации и +. Да если одно из этим предположений не верное, то и все решение ошибочно, но я не вижу смысла в данном подходе.
Talk is cheap. Show me the code.
Re[22]: [Зависимые типы] Объясните на пальцах.
От: SergH Россия  
Дата: 03.07.09 14:44
Оценка:
Здравствуйте, dotneter, Вы писали:

D>sum x y = x + y

D>Предполагается правильность спецификации и +.

+ это нижний уровень относительно sum. Я говорю про верхний.
Делай что должно, и будь что будет
Re[20]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 15:04
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Это баг спецификации а не реализации.


А вот это уже никого кроме философов не трогает. Баг — это работа программы не так как предполагает ее пользователь.
Если тривиальщину выразить трудно, то что делать со сложным софтом?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[21]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 15:08
Оценка:
Здравствуйте, SergH, Вы писали:

SH>Реализация более верхнего уровня это спецификация для более нижнего. Реализация на С это спецификация для компилятора. Машинный код, генерируемый компилятором это спецификация для процессора. Микрокод инструкции это спецификация для кусочков процессора... Ниже, пожалуй некуда, ниже сильно всё меняется, да и про микрокод я уже не уверен.


Не. Спецификация не подразумевает полное описание системы. Спецификация всегда подразумевает умолчания и упрощения. Маш.код и ассемблер — это просто разные представления одного и того же. С-и и ассемблер тоже. Но С ближе к людям. В прочем в С уже есть некоторые умолчания, но они формализованы стандартом языка.

Именно по этому спецификации пишутся на неформальных языках и претворяются в жизнь программистами. Иначе мы имеем некий ДСЛ для которого нужно всего лишь написать транслятор. В таком случае доказать нужно уже не корректность программы, а корректность кодогенератора и ДСЛ-я.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 15:14
Оценка:
G>>>Можно ли записать композицию sort >> otherFunc (или как оно там пишется) или нужны еще какие-то телодвижения?

T>>Нужны телодвижения.

G>И как они будут выглядеть?

Мы можем автоматически получить преобразование из спископодобной структуры в список. Это сделает компилятор. См. Generic programming with dependent types.

Использование любой спископодобной (даже чисел Пеано!) структуры как параметра-списка сведётся к вызову этого автоматического преобразования.

Иными словами: onSortedList soertList = ... (onSimpleList (toList soertedList)) ...
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[7]: [Зависимые типы] Объясните на пальцах.
От: VoidEx  
Дата: 03.07.09 15:21
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Ты видимо не понял. Если можно написать спецификацию поведения некоторого объекта, то эта спецификация будет не проще самого кода объекта, вероятнее всего гораздо сложнее. Как потом доказать что спецификация написана без ошибок?

Это чисто интуитивная мысль, или есть какие-то подтверждения?
Спецификация отсортированного списка, как было видно на примере, на порядки проще сортировки. Так что "вероятнее всего" стоит здесь вероятнее всего не к месту.
Re[8]: [Зависимые типы] Объясните на пальцах.
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 03.07.09 15:27
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Здравствуйте, gandjustas, Вы писали:


G>>Ты видимо не понял. Если можно написать спецификацию поведения некоторого объекта, то эта спецификация будет не проще самого кода объекта, вероятнее всего гораздо сложнее. Как потом доказать что спецификация написана без ошибок?

VE>Это чисто интуитивная мысль, или есть какие-то подтверждения?
Интуитивная.

VE>Спецификация отсортированного списка, как было видно на примере, на порядки проще сортировки. Так что "вероятнее всего" стоит здесь вероятнее всего не к месту.

Спецификация списка != спецификация алгоритма сортировки.

В любом случае полная (а иначе она нам не поможет) спецификация поведения кода будет не меньше (и не проще) самого кода.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 15:53
Оценка:
Здравствуйте, thesz, Вы писали:

VD>>К тому же я практически уверен, что юнит-тесты от этого не исчезнут. Юнит-тесты проверяют поведение, а описать поведение статически просто невозможно. Это и есть код.


T>Боже ж мой.

T>Код и есть статическое описание поведения.
T>То есть, мы статически — кодом, ведь код-то не меняется во время исполнения, — описываем поведение программы.
T>Таким образом, поведение описывается исключительно статическим образом. Даже если это тесты.

Если исходить из этого, то прав SergH
Автор: SergH
Дата: 03.07.09
, в том смысле, что багов не бывает.

T>Я бы понял, если бы ты сослался на проблему останова, но ты же про неё не знаешь, ведь так?


Знаком. Только я не о том. Я о том, что спецификации большинства программ не формальны. Их не выразить в системе типов. Точнее задача выражения может оказаться сложнее задачи реализации. А формальные спецификации можно (как верно заметил SergH) превратить в корректные программы написав годогенератор. Это будет во много раз проще.

Юнет-тесты тем и хороши, что проверяют важные для пользователей факты. В прочем, случалось видеть и совершенно бессмысленные юнит-тесты проверяющие правильность работы ALU. Но это уже проблемы тугодумов.

В общем, теория очень далека от практики. Я не раз был свидетелем того, как очень красивые мечты разбивались о суровую действительность.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: VoidEx  
Дата: 03.07.09 16:02
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Спецификация списка != спецификация алгоритма сортировки.

Это просто придирка или ты намекал, что List a -> SortedList a сложнее самой сортировки?
Re[4]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.07.09 16:47
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Эту кракозябру можно написать немного короче:

WH>
WH>zip : forall{A B n} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
WH>


Кстати, так уже намного лучше. Это гипотетический синтаксис или Агда?

Не ясно только зачем нужен "forall{A B n} -> ". Это объявление явно лишнее и сбивает с толку.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 22:12
Оценка:
T>>Таким образом, поведение описывается исключительно статическим образом. Даже если это тесты.

VD>Если исходить из этого, то прав SergH
Автор: SergH
Дата: 03.07.09
, в том смысле, что багов не бывает.


T>>Я бы понял, если бы ты сослался на проблему останова, но ты же про неё не знаешь, ведь так?


VD>Знаком. Только я не о том. Я о том, что спецификации большинства программ не формальны. Их не выразить в системе типов.

VD>Точнее задача выражения может оказаться сложнее задачи реализации.

Может? А может не оказаться? А каково соотношение этих двух случаев?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[7]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 03.07.09 22:20
Оценка:
VD>В общем, теория очень далека от практики. Я не раз был свидетелем того, как очень красивые мечты разбивались о суровую действительность.

Вдогонку.

То, что делает здоровенный код на Си, легко и кратко выражается спецификацией на языке Хаскель. Из которого код на Си и создаётся.

Не надо сбрасывать со счётов уровень языка.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[5]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 03.07.09 22:51
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Проблема в том, что описание получилось в несколько раз сложнее самой функции.

Чё там сложное? Там все максимально просто и полностью декларативно.

VD>ОК. А что мы контролировали? И нельзя ли выразить это более просто?

Что длины входищих и исходящего списков идентичны.

VD>Я бы так не сказал. В немероловм варианте есть простор для фантазии

Ага. Для багов.

VD>(так как реализация не приведена).

А строчкой ниже что?

VD>Списки могут различаться по длине и при этом реализация может реагировать по разному:

VD>1. Выдать исключение.
VD>2. Отбросить "лишние" элементы из более длинного списка.
VD>По жизни второй вариант будет более востребован, хотя потребоваться могут оба.
Нахрена?
ИМХО единственный разумный вариант в случае списков разной длинны это ошибка времени компиляции.

VD>Код который нужно добавить, чтобы получить п. 1. не сложен:

VD>
VD>zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
VD>  requires l1.Lenght == l2.Lenght
VD>  ensures  value.Lenght == l1.Lenght
VD>

Это блин называется не сложный... ты на оригинал еще раз посмотри да.
Там все полностью декларативно.

VD>А вот со статической проверкой будут проблемы, так как списки могут формироваться динамически, и их длинна, в общем случае, не известна во время компиляции.

Прелесть зависимых типов в том что они прекрасно работают в данном случае...

VD>Как эти проблемы решаются в Агде?

Какие проблемы?

VD>Я повторюсь, но мне не понятно, как компилятор сможет проверить работу со списками большая часть которых получается динамически?

VD>Или мы будем работать отдельно с динамическими списками (и при этом все проверки пойдут на смарку), и отдельно со статическими?
Ты точно не понял что к чему.

VD>Я пока ничего не говорю. Я просто констатирую факт, что то что ты привел — это весьма туманно, сложно и при этом не понятно решает ли исходные задачи.

Непривычно? Да.
Сложно? Нет.
Решает.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[7]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 03.07.09 23:07
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Многословность != непонятность. Сравним два варианта:

VD>
VD>zip : {n : Nat} -> {A : Set} -> {B : Set} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
VD>

VD>и
VD>
VD>zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
VD>  requires l1.Lenght == l2.Lenght
VD>  ensures  value.Lenght == l1.Lenght
VD>

Сравнил. Мне первый понятнее.
Более того он формален в доску чего не скажешь о костылях во втором случае.

VD>Приведенный тобой пример описания типа функции в двое длиннее тела функции и в 10 раз не понятнее (на мой взгляд).

Ну давай запишем это в более привычном тебе виде:
zip{A, B, n}(l1 : Vec A n, l2 : Vec B n) : Vec (A * B) n

С синтаксисом можно обходится весьма вольно.

VD>Кучу ли?

Ага.

VD>Что у нас с динамическими списками? Что у нас с вводом / выводом?

А что с ними?

VD>Что, наконец с логикой? Как в систему типов загнать информацию о поведении не тривиального кода?

Берешь и загоняешь. Декомпозицию никто не отменял.

VD>Я не заметил чего-то выносящего мозг. Видимо по второму разу данная трава уже не так выносит .

VD>Я заметил "много букв" при не вполне понятном результате.
Много букв это у тебя. И результат не понятен опять таки тебе.

VD>Я не догматик и умею менять свое мнение. Пока что оно умеренно скептическое. В прочем, скепсис скорее относится к синтаксису и возможностям, а не к самой идее.

С синтаксисом можно сделать все что угодно. И ты не хуже меня жто знаешь.
А возможности у этой механики очень большие.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: [Зависимые типы] Объясните на пальцах.
От: dotneter  
Дата: 04.07.09 07:55
Оценка:
Здравствуйте, WolfHound, Вы писали:

VD>>Как эти проблемы решаются в Агде?

WH>Какие проблемы?

Наверное имелось в виду
listA = getListA (void -> Vec A n)
listB = getListB (void -> Vec B n)

zip listA listB // как тут компилятор понимает какой длинны listA и listB
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Talk is cheap. Show me the code.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 04.07.09 08:07
Оценка:
Здравствуйте, dotneter, Вы писали:

D>Здравствуйте, WolfHound, Вы писали:


VD>>>Как эти проблемы решаются в Агде?

WH>>Какие проблемы?

D>Наверное имелось в виду

D>
D>listA = getListA (void -> Vec A n)
D>listB = getListB (void -> Vec B n)

D>zip listA listB // как тут компилятор понимает какой длинны listA и listB
D>


Делаем проверку на равенство. Если равны, то можно zip. Не равны, отрежем кого. Или приклеим кому.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[9]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 04.07.09 08:16
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, VoidEx, Вы писали:


VE>>Здравствуйте, gandjustas, Вы писали:


G>>>Ты видимо не понял. Если можно написать спецификацию поведения некоторого объекта, то эта спецификация будет не проще самого кода объекта, вероятнее всего гораздо сложнее. Как потом доказать что спецификация написана без ошибок?

VE>>Это чисто интуитивная мысль, или есть какие-то подтверждения?
G>Интуитивная.

А желательно бы иметь опыт. Тем более, что в этом нет ничего сложного.

VE>>Спецификация отсортированного списка, как было видно на примере, на порядки проще сортировки. Так что "вероятнее всего" стоит здесь вероятнее всего не к месту.

G>Спецификация списка != спецификация алгоритма сортировки.
G>В любом случае полная (а иначе она нам не поможет) спецификация поведения кода будет не меньше (и не проще) самого кода.

Во-первых, можно приближаться к полной спецификации сколь угодно близко исходя из текущих надобностей. Во-вторых, Why dependent types matter, стр 9 и стр 21. Сортировка векторов слиянием, сама функция слияния с доказательством сохранения размера и с доказательством получения упорядоченного вектора. От самого алгоритма слияния отличается только наличием типов. Как и было сказано выше, большинство действий определяются небольшим количество информации из внешней спецификации.

Тут очень интересно вот, что: от тестов ты требуешь практических результатов, а от типов — теоретически достижимых.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[12]: [Зависимые типы] Объясните на пальцах.
От: Аноним  
Дата: 04.07.09 12:39
Оценка:
Здравствуйте, deniok, Вы писали:

D>Здравствуйте, dotneter, Вы писали:


D>>Здравствуйте, Alexey Romanov, Вы писали:


AR>>>Но нам ничто не мешает написать функцию

AR>>>
AR>>>zip' : (Vec A n) -> (Vec B m) -> (Vec (A,B) (min n m))
AR>>>

AR>>>которая соответствует второму варианту VladD2.
D>>Нам то ничего не мешает написать все что угодно, но поинт то был в том что бы zip принимал только списки одинаковой длинны и ругался при компиляции если это не так.

D>Ну именно так всё и есть. Ты не можешь встроить вызов zip в то место, где нет статической гарантии "равнодлинности" векторов-параметров. Если их нет, то ты либо должен обеспечить такие гарантии ручками (скажем, обеспечив механизм параллельного чтения элементов списка из файлов, по построению гарантирующего равную длину векторов), либо пользоваться версией zip', которая игнорирует хвост длиннейшего.


Именно.
Re[11]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 04.07.09 18:11
Оценка:
AR>>Но нам ничто не мешает написать функцию
AR>>
AR>>zip' : (Vec A n) -> (Vec B m) -> (Vec (A,B) (min n m))
AR>>

AR>>которая соответствует второму варианту VladD2.
D>Нам то ничего не мешает написать все что угодно, но поинт то был в том что бы zip принимал только списки одинаковой длинны и ругался при компиляции если это не так.

http://thesz.livejournal.com/860912.html?thread=6304240#t6304240

Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[9]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 06.07.09 07:55
Оценка:
Здравствуйте, gandjustas, Вы писали:

T>>Перечисли, пожалуйста, что же можно проверить контектом.

G>Много чего, только не получится расширить существующие типы для обеспечения проверок. Поэтому упорядоченность списка не получится прверить.

А если без расширения. Написать свой, в котором контракты гарантируют упорядоченность элементов, можно?
Re[8]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.07.09 18:35
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, VladD2, Вы писали:


VD>>Многословность != непонятность. Сравним два варианта:

VD>>
VD>>zip : {n : Nat} -> {A : Set} -> {B : Set} -> (l1 : Vec A n) -> (l2 : Vec B n) -> Vec (A, B) n
VD>>

VD>>и
VD>>
VD>>zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
VD>>  requires l1.Lenght == l2.Lenght
VD>>  ensures  value.Lenght == l1.Lenght
VD>>

WH>Сравнил. Мне первый понятнее.

Ну, что же. Можешь радоваться, так как ты вместе с еще 3 человеками сможешь в этом во всем разбираться.
Лично я очень не хотел бы по пол часа въезжать в объявление примитивной функции. Все же граничные условия — это дело десятое. Контролировать их конечно полезно, но знать о них чтобы программировать не обязательн.

WH>Более того он формален в доску чего не скажешь о костылях во втором случае.


Формальность — это хорошо для компьютера, или для писателя компилятора. А вот для человека важна простата понимания.

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

VD>>Приведенный тобой пример описания типа функции в двое длиннее тела функции и в 10 раз не понятнее (на мой взгляд).

WH>Ну давай запишем это в более привычном тебе виде:
WH>
WH>zip{A, B, n}(l1 : Vec A n, l2 : Vec B n) : Vec (A * B) n
WH>

WH>С синтаксисом можно обходится весьма вольно.

Я не сказал бы, что приведенный пример привычен, но он куда короче и понятнее (но без домысливания не обойтись). Отличие B от n без пояснений не видать. Плюс не ясно, что такое Vec? Ну, и синтаксис тоже весьма привычный.
Возможно как-то так было бы понятнее:
zip[A, B, len : int](l1 : list[A, len], l2 : list[B, len]) : list[A * B, len]

В прочем — это тоже довольно громоздко.

Ну и вопрос о то, что будет в случае динамического формирования списка так же остается открытым. Как проверить тело по сигнатуре в обще ясно, но как проверить все вызовы этого метода?

VD>>Что у нас с динамическими списками? Что у нас с вводом / выводом?

WH>А что с ними?

Это бы вопрос к тебе. Ты упорно обходишь ответ на него.

VD>>Что, наконец с логикой? Как в систему типов загнать информацию о поведении не тривиального кода?

WH>Берешь и загоняешь. Декомпозицию никто не отменял.

Я не вижу в твоих примерах декомпозиции.

Вот если бы эти зависимости можно было выражать как-то по другому...
Например, при описании списка мы указываем, что у него есть один неявный параметр типам целочисленного типа, и что он связан со значением свойства Length. Тогда приведенный пример можно было бы описать очень просто и изящно:
zip[A, B](l1 : list[A], l2 : list[B]) : list[A * B]
  types invariant l1.Lenght = l2.Lenght = result.Lenght
{
  ...
}

Это было бы и кратко, и понятно не посвященным.

VD>>Я не заметил чего-то выносящего мозг. Видимо по второму разу данная трава уже не так выносит .

VD>>Я заметил "много букв" при не вполне понятном результате.
WH>Много букв это у тебя. И результат не понятен опять таки тебе.

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

WH>С синтаксисом можно сделать все что угодно. И ты не хуже меня жто знаешь.


Дык очень важно найти оптимальный синтаксис. Иначе это так и останется академической игрушкой.

WH>А возможности у этой механики очень большие.


Ну, так дава начнем с объяснения того как статические проверки будут работать для динамически получаемых данных.
Скажем есть у нас функция возвращающая список введенных пользователем чисел:
GetData[int, n : int]() : list[int, n]

и есть твой Zip:
Zip[A, B, len : int](l1 : list[A, len], l2 : list[B, len]) : list[A * B, len]

И мы пишем:
def res = Zip(GetData(), GetData());
WriteLine(res);

Как на это отреагирует компилятор?
Если не даст скомпилировать, то как нам написать рабочий вариант?

ЗЫ

Кстати, идея PRG-парсера умерла так и не родившись?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 20:36
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Есть разные способы, например, мы можем написать функцию, проверяющую — одинаковая ли длина у списков, и если одинаковая вызвать нашу функцию склейки. Компилятор это дело пропустит, т.к. в данном месте будет доказано, что у списков одинаковая длина.


То есть, мы усложняем код вводя дополнительные функции и проверки?

VD>>Сложно. Много шума. Это видно очень отчетливо. Возможно все тоже самое можно было бы записать в несколько раз проще.


L>Тут ещё не раз не показали как это можно сделать. А то, что зависимые типы сокращают и упрощают код было уже показано несколько раз.


Где это было показан?

VD>>Но в таком виде функцию по сложнее уже будут воспринимать далеко не все.


L>Мне ужасно не нравится этот аргумент. Мне кажется, подобные утверждения тормозят развитие. Не надо ориентироваться только на троечников. Не надо, чтобы эту функцию воспринимали все.


Высказывание не может тормозить развитие. Я или ошибаюсь, или нет. Если нет, то идею не примут и ею будет пользоваться узкая группа лиц которая в своих предпочтениях удобство поставит ниже надежности.

L>P.S. Зависимые типы — это следующий шаг после Хиндли-Милнера, который есть следующий шаг после статической типизации


Хиндли-Милнера? Вы меня извините, но в этой системе типов нет ничего выдающегося. В чистом виде она не удобна и весьма убога. А зависимые типы по идее могут применяться с любой системой типов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: VoidEx  
Дата: 07.07.09 21:00
Оценка:
Здравствуйте, VladD2, Вы писали:

L>>Есть разные способы, например, мы можем написать функцию, проверяющую — одинаковая ли длина у списков, и если одинаковая вызвать нашу функцию склейки. Компилятор это дело пропустит, т.к. в данном месте будет доказано, что у списков одинаковая длина.


VD>То есть, мы усложняем код вводя дополнительные функции и проверки?


Нет, мы упрощаем код, вводя проверку всего один раз на самом верху (ну или в нужном, но одном месте).
В обычном случае нам приходится постоянно проверять на null, либо знать, что может вылететь NPE (это фактически встроенная та самая дополнительная функция с проверкой, которую ты упомянул), а тут проверку заставляет сделать компилятор, но всего один раз, а дальше мы уже знаем, что ссылка not null.
Это как пример.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 21:08
Оценка:
Здравствуйте, Alexey Romanov, Вы писали:

AR>Если имеется ввиду, что getListA имеет тип IO (Vec A n), то это сокращённая запись для {forall A n}(IO (Vec A n)), то есть getListA обещает вернуть список любой длины и любого типа, который нужен. Естественно, чтение из файла такого типа иметь не будет. А будет оно иметь тип

AR>
AR>IO {exists n}(Vec A n)
AR>IO {exists n}(Vec B n)
AR>

AR>То есть возвращается список некоторой натуральной длины. Естественно, эти n могут быть разными.

AR>Но нам ничто не мешает написать функцию

AR>
AR>zip' : (Vec A n) -> (Vec B m) -> (Vec (A,B) (min n m))
AR>

AR>которая соответствует второму варианту VladD2.

Вот это уже конструктив! Я вообще, поражаюсь с умений некоторых наших завсегдатаев вместо объяснений разводить флуд.

Стало быть над аргументами типов можно производить вычисления?
Если так, то не приведет ли это к проблемам С++ когда систему типов нечнут использовать как мета-язык вместо того, чтобы использовать ее по назначению?

Еще вопрос...
Как будет выглядеть код с проверками. Скажем, что у нас и правда есть два файла и мы предполагаем, что в 99.999% случаев в них будет одинаковое количество элементов. Но файл может быть, скажем так, испорчен и потенциально длинна может оказаться разно.
Напиши гипотетический код который читает эти файлы и склеивает их результат (разумеется с проверками).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 21:11
Оценка:
Здравствуйте, deniok, Вы писали:

D>Ну именно так всё и есть. Ты не можешь встроить вызов zip в то место, где нет статической гарантии "равнодлинности" векторов-параметров. Если их нет, то ты либо должен обеспечить такие гарантии ручками (скажем, обеспечив механизм параллельного чтения элементов списка из файлов, по построению гарантирующего равную длину векторов), либо пользоваться версией zip', которая игнорирует хвост длиннейшего.


Но есть третий вариант. Случай когда длинны различаются может быт рантайм-ошибкой. Вероятность ее появления ничтожно мала, но есть. И программист может предпочесть версию которая будет лениво читать содержимое файлов и лениво склеивать их, а в случае расхождения длин генерировать исключение.
Такое поведение мы можем описать с помощью зависимых типов.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 21:21
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>То есть, мы усложняем код вводя дополнительные функции и проверки?


Усложняем по сравнение с чем? Все эти дополнительные проверки мы пишем и с контрактами, только работать и ломаться код с контрактами будет в рантайме.
Вернёмся к рассматриваемому примеру — ты описал на контрактах функцию склеивающую два списка одной длины. И посмотри, что ты будешь делать с ней, когда списки получены динамически, может так тебе будет проще взглянуть на тот же пример со стороны ЗТ.

VD>>>Сложно. Много шума. Это видно очень отчетливо. Возможно все тоже самое можно было бы записать в несколько раз проще.

L>>Тут ещё не раз не показали как это можно сделать. А то, что зависимые типы сокращают и упрощают код было уже показано несколько раз.
VD>Где это было показан?

Ну как же, одной строчкой заменяем кучу юнит тестов — сокращение. Простой и явной декларацией в типах заменяем мутные контракты, описывающие ограничения реализации — упрощение.

VD>Высказывание не может тормозить развитие. Я или ошибаюсь, или нет. Если нет, то идею не примут и ею будет пользоваться узкая группа лиц которая в своих предпочтениях удобство поставит ниже надежности.


Я что хочу сказать — нам не должно быть дело до того, чтобы написаное нами воспринималось всеми. Инструмент должен быть полезен, удобен, понятен в работе в первую очередь тому, кто будет писать и поддерживать код.

VD>Хиндли-Милнера? Вы меня извините, но в этой системе типов нет ничего выдающегося. В чистом виде она не удобна и весьма убога. А зависимые типы по идее могут применяться с любой системой типов.


Возможно. Я не очень близко знаком с зависимыми типами, для меня это лямбда-P из лямбда-куба. Т.е. её применение я пока вижу только в чистых системах типов (PTS).
Re[11]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 21:28
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Я уверен, что зависимые типы ничем не могут помочь с NRE. Более того эта проблема легко решается (и, кстати сказать, отсуствует в ОКамле и Хаскеле) самой системой типов. Достаточно описать допускающие null типы и не допускающие, а так же описать возможность явного и/или не явного преобразования между ними. Далее для переменных не допускающих null типов компилятор должен требовать инициализацию.


Да, согласен, зависимые типы не очень-то нужны для решения NPE. С другой стороны есть схожие проблемы — например, работать с ресурсом, будучи уверенным, что он инициализирован и не освобождён, или уже приводившийся пример с решением проблемы дедлока. Ну и кучу всего можно придумать, где типы выгодно индексировать.

VD>Кстати, на мой взгляд проблема NRE создает куда больше проблем на практике. Вот ее бы решить в мэйнстриме!


Re[11]: [Зависимые типы] Объясните на пальцах.
От: VoidEx  
Дата: 07.07.09 21:34
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Я уверен, что зависимые типы ничем не могут помочь с NRE.

Ну почему же. Если обращение по ссылке (т.е. сама .) будет требовать доказательсвта ненулёвости, то выхода будет всего два:
1. Требовать такое док-во самому (т.е. указывать в декларации функции, что ты принимаешь только ненулевой указатель)
2. Делать проверку на null и обрабатывать ошибку. Разумеется, в кач-ве обработки можно кинуть исключение, но это уже не будет NRE, потому что если ты не знаешь, что делать с null — выбери пункт 1, а если знаешь, то обработка будет осмысленной.

Отличие от обычных исключений в том, что там проверка на null неявная и делается всегда, потому что даже убедившись, что указатель ненулевой, ты никак сей факт зафиксировать не можешь.
Re[11]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 21:35
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Стало быть над аргументами типов можно производить вычисления?

VD>Если так, то не приведет ли это к проблемам С++ когда систему типов нечнут использовать как мета-язык вместо того, чтобы использовать ее по назначению?

Так система типов — это та же лямбда! Почему бы над ней и не попроводить вычисления? Единственное отличие — язык системы типов должен быть тотальным.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 21:38
Оценка:
Здравствуйте, lomeo, Вы писали:

VD>>Не ясно только зачем нужен "forall{A B n} -> ". Это объявление явно лишнее и сбивает с толку.


L>Ну, вот видишь Vec, он с внешнего контекста, т.е. определён где-то снаружи, а forall говорит, что типы A,B,n искать снаружи не надо — это типы-переменные. Пример — В Haskell forall не пишется потому, что типы-переменные выделяются синтаксически — у них первая буква строчная. Т.е. это вопрос синтаксиса. Вполне возможен синтаксис, когда forall писать не обязательно — нашёл снаружи тип с таким именем — значит, это конкретный тип, не нашёл — тип-переменная. Но по вполне понятным причинам такой синтаксис нам не нужен


Дык переменные типы можно описывать в скобках как в С++, Яве и дотнете. Выкидываем "forall{A B n} ->" и добавляем "zip<A, B, n>".
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 21:51
Оценка:
Здравствуйте, VladD2, Вы писали:

T>>Делаем проверку на равенство. Если равны, то можно zip. Не равны, отрежем кого. Или приклеим кому.

VD>То есть верифицировать весь код и заставлять писать все проверки?

Не больше, чем обычно.

VD>А не офигеш ли это делать?

VD>Исключения придумали для того, чтобы когда пишешь логику по меньше думать о редких граничных условиях. Если проверять все, то код может разбухнуть очень и очень сильно.

Про то, для чего придумали исключения, любит рассказывать thesz, поэтому я вежливо промолчу

VD>Кто-нибудь проводил сравнение трудозатрат вызванных тестированием и вызванных тотальными проверками всех нюансов?


Да нет же, тут в чём прикол — небольшой декларацией ты гарантируешь, что функция sortSomething вернёт отсортированную структуру, то же самое на более пузатых юнит-тестах ты просто не сделаешь, а контракты, которые не будут такими небольшими, смогут сработать только в рантайм. О каких трудозатратах идёт речь?

Ну и разумеется, почему это ЗТ должны заниматься тотальными проверками всех нюансов, а тестирование не всех? После этого просто нечестно сравнивать трудозатраты.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 21:51
Оценка:
Здравствуйте, lomeo, Вы писали:


L>Так система типов — это та же лямбда! Почему бы над ней и не попроводить вычисления?


Потому, что результат печальный выходит. В коде могут разобраться 1-2 процента программистов, а остальные тихо ...
Для МП должны быть явные и простые средства. Система же типов должна уменьшать количество ошибок и предоставлять метаиформацию (рефлексия, интелисенс в IDE и т.п.).

L>Единственное отличие — язык системы типов должен быть тотальным.


Переведи.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 21:55
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Дык переменные типы можно описывать в скобках как в С++, Яве и дотнете. Выкидываем "forall{A B n} ->" и добавляем "zip<A, B, n>".


А ты про это! Ну это уже вопрос синтаксиса, мне не очень интересно, если честно.
Re[11]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 07.07.09 22:11
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Дык там есть множество нюансов. Иногда проще забить на проверки времени компиляции и воспользоваться проверками времени выполнения.

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

Ну да, точно так же и с ЗТ. Зависит от ситуации, что именно ты будешь делать. Предложенное мной решение — всего лишь один из вариантов.

VD>Да, ну. В юнит-тесте я убду проверять большой блок функциональности и при этом, возможно, не напишу кучи совершенно не нужных проверок (которые заставит меня написать система типов с зависимостями).


Возможно, я где-то что-то упустил. Насколько я понимаю, идёт сравнение того, что и как выражается с помощью ЗТ и юнит-тестов? Если да, то зачем нам писать ненужные проверки при ЗТ и не писать при юнит-тестах?

VD>Без специального исследования утверждать, что кода получится меньше я бы не стал. В общем, это весьма голословное утверждение.


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

VD>Что до надежности, то припоны которые начнет чинить компилятор (а программист именно так это будет воспринимать) начнут обходиться разными путями. Так что ошибки никуда не денутся. Да и ошибки бывают логичекими. Ну, не верный алгоритм. И что тут компилятор скажет? Он же не знает как надо? Для него верен тот алгоритм который может скомпилироваться.


Ну, тут ничто не поможет, давай всё таки сравнивать аналогичное.

VD>В первую очередь должна быть польза. Польза обществу. Если человек будет считать, что инструмент куль и круть, а на деле он начнет писать программы в 10 раз медленнее, то всем будет по фигу, что нужно вам. Всем будет очевидно, что от этого инструмента больше вреда нежели пользы, а те кто им занимаются просто заигрались в игрушки.


Не понимаю аргументации. Я вот в vim-е пишу очень много кода. Это очень удобный инструмент. От него польза мне, а не обществу.
Если же ты имеешь в виду, что код с ЗТ писать медленнее, то могу поделиться только своим небогатым опытом. Индексированные типы и open functions (это "почти" ЗТ в Haskell) облегчают мне написание кода. Ощущение свободы больше, когда ограничения накладываются более явно.

VD>Я вижу, что зависимые типы спокойно прокатят и в номинальной системе типов с подтипами а-ля С++/Ява/дотнет.


Сорри, не компетентен я в этом, возможно, прокатят, я не вижу как.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 22:27
Оценка:
Здравствуйте, Alexey Romanov, Вы писали:

VD>>Я не сказал бы, что приведенный пример привычен, но он куда короче и понятнее (но без домысливания не обойтись). Отличие B от n без пояснений не видать. Плюс не ясно, что такое Vec? Ну, и синтаксис тоже весьма привычный.

VD>>Возможно как-то так было бы понятнее:
VD>>
VD>>zip[A, B, len : int](l1 : list[A, len], l2 : list[B, len]) : list[A * B, len]
VD>>

VD>>В прочем — это тоже довольно громоздко.

AR>Это приемлемо. Но учитывая, что квадратные и круглые скобки различают только выводимые и явные параметры, а не параметры типов и функций.


Это почему? Я использовал синтаксис немерла. В нем квадратные скобки аналогичны скобкам < > из С++.
Так что в квадратных скобках у меня как раз объявлены переменные типов.

Согласен, что int не очень строго. Но в реальных компьютерах где переполнение целых норма лучше получить отрицательных индекс, чем переполнение.
В прочем это детали. Можно заменить int на uint.

AR>Type вместо агдовского Set. int тут тоже в общем-то не при деле, поскольку списков с отрицательной длиной не бывает -- но это ладно. Единственная причина, по которой в C#/Nemerle/Haskell не нужно указывать, что A и B типы -- это отсутствие других возможностей. Можно попробовать грязный хак вроде "все параметры функции или типа, тип которых не указан, имеют тип Type", но идея так себе.


Дык в C#/Nemerle параметры типов как раз задаются явно. Первые квадратные скобки — это как раз их описание. Считай тот же forall. А уже внутри описания параметров и возвращаемого значения — это аргументы. Просто область видимости.

AR>В "инвариантах" может быть далеко не только равенство, а любые условия. Так что скорее инвариант должен выглядеть как
l1.Length == l2.Length, l1.Length == result.Length
Уже хуже.


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

AR>Неявные параметры для типов -- это понятно непосвящённым?


Мне кажется это будет проще объяснить. В прочем — это не более чем идея не претендующая на истину.

AR>Почему неявный параметр -- именно длина, а не (например) первый элемент списка?


Потому что в этом есть смысл для данной структуры данных.

AR>Мне не хотелось бы каждый раз раз лезть в определение списка и выяснять, какие свойства можно использовать в инвариантах, а какие -- нет.


А мне вообще не хотелось бы никуда лезть, и не хотелось бы разбираться в трехметровом описании типа. Мне хотелось бы, чтобы в случае кода я ошибаюсь, чтобы компилятор бил меня по рукам.

AR>Давай ещё сделаем A и B неявными:

AR>zip(l1 : list, l2 : list) : list
AR> types invariant l1.Length == l2.Length, l1.Length == result.Length,
AR> value.Type == l1.Type * l2.Type
AR>{
AR> ...
AR>}
AR>[/c#]
AR>По-моему, это не стало ни понятнее, ни короче. Точно так же вариант с длиной как неявным параметром мне не нравится.

Какие-то они не очень не явные.
Ты просто перенес описание типов в свойство (или поле).

VD>>Ну, так дава начнем с объяснения того как статические проверки будут работать для динамически получаемых данных.

VD>>Скажем есть у нас функция возвращающая список введенных пользователем чисел:
VD>>
GetData[int, n : int]() : list[int, n]


AR>Эта функция обещает вернуть список любой нужной длины.


То есть параметр n я должен задать явно или он может быть выведен из сигнатуры той функции коду передается результат этой?
ОК.

AR>Функция, которая возвращает список некоторой неизвестной длины, может иметь тип

AR>
GetData() : (n : int) * list(int, n)


Т.е. возвращать длину в кортеже и потом нужно матчить это дело, чтобы понять, что к чему?

AR>либо использовать старый тип для списков произвольной длины (который, естественно, никуда не денется от расширения системы типов).


И они не будут совместимы и мы опять будем вынуждены матчить (т.е. делать тонны проверок) и преобразовывать типы явно?

AR>А для этого нужно решить, что считать рабочим вариантом. Как эта функция должна себя вести, если списки имеют разную длину?

AR>[q]
AR>Main() : void
AR>{
AR> def (_,data1) = GetData();
AR> def (_,data2) = GetData();
AR> def res = Zip1(GetData(), GetData());
AR> WriteLine(res);
AR>}
AR>[/c#]

А зачем тут строки:
AR> def (_,data1) = GetData();
AR> def (_,data2) = GetData();
?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 22:30
Оценка:
Здравствуйте, VoidEx, Вы писали:

VD>>Более того. Ну, представим компилятор заставил меня обрабатывать какие-то несоответствия. ОК. А как я их обработаю? Ну, не сошлась у меня длинна двух списков перед вызовом zip-а. И что мне делать? Исключения кидать? Дык, а зачем я тогда пишу код проверок? Пусть его кидает сам zip.

VD>>Писать какой-то код реакции? Дык это может резко увеличить объем работы и при этом один хрен многие схалтурят и напишут какую-нибудь ересь.

VE>Эм, а без зависимых типов ты как с такими бедами справляешься? Оставляешь на самотёк что ли?


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

Тут надо понять, что код можно писать или быстро, или скрупулезно. Иногда нужно последнее, но чаще (мне по крайней мере) первое.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.07.09 22:43
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Система типов должна описывать ограничения. Ограничения очень хорошо описываются выражениями, над выражениями обычно производятся вычисления.


С этим я согласен. Но, я о другом говорю, о том, что вычисления над типами не должны приводить к другим эффектам. К генерации кода как в шаблонах С++. Или к посылке мыла на почтовый ящик.

L>Что касается 1-2 процентов программистов — почему тебя это так волнует? Ты же себе инструмент должен подобрать, а не 98-99% программистов.


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

Потом это только ты можешь писать код в vim-е. А мне нужен рефакторин, система управления проектами, подсветка не только синтаксиса, но и интеллектуальная подсветка типов, хороший отладчик и т.д. и т.п. А это все банально не сделают для языка который понимают пара сотня человек в мире.

Так что к хорошей идее, а ТЗ смахивает на нее, нужно еще хорошее обрамление.
Сори за аналогию, но с алмазов прет только узкую группу специалистов, а с бриллиантов весом в пару каратов прет большую часть человечества .
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: [Зависимые типы] Объясните на пальцах.
От: Alexey Romanov  
Дата: 08.07.09 08:01
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Alexey Romanov, Вы писали:


VD>>>Я не сказал бы, что приведенный пример привычен, но он куда короче и понятнее (но без домысливания не обойтись). Отличие B от n без пояснений не видать. Плюс не ясно, что такое Vec? Ну, и синтаксис тоже весьма привычный.

VD>>>Возможно как-то так было бы понятнее:
VD>>>
VD>>>zip[A, B, len : int](l1 : list[A, len], l2 : list[B, len]) : list[A * B, len]
VD>>>

VD>>>В прочем — это тоже довольно громоздко.

AR>>Это приемлемо. Но учитывая, что квадратные и круглые скобки различают только выводимые и явные параметры, а не параметры типов и функций.


VD>Это почему? Я использовал синтаксис немерла. В нем квадратные скобки аналогичны скобкам < > из С++.


Потому что для зависимых типов разница между параметрами типов и функций несущественна. У zip не 3 генерик-параметра и 2 аргумента функции, а просто 5 аргументов.

Но чтобы при использовании (а не объявлении) функций избежать громоздкости, нужно ввести неявные аргументы. A, B, и len мы всегда можем извлечь из типа l1 и l2, поэтому они могут передаваться неявно.

Какое-то обозначение для неявных параметров нам нужно, а C#/Nemerle как раз позволяет вывод генерик-параметров (иногда).

VD>Так что в квадратных скобках у меня как раз объявлены переменные типов.


len -- не переменная типа по-любому.

VD>Согласен, что int не очень строго. Но в реальных компьютерах где переполнение целых норма лучше получить отрицательных индекс, чем переполнение.

VD>В прочем это детали. Можно заменить int на uint.

AR>>Type вместо агдовского Set. int тут тоже в общем-то не при деле, поскольку списков с отрицательной длиной не бывает -- но это ладно. Единственная причина, по которой в C#/Nemerle/Haskell не нужно указывать, что A и B типы -- это отсутствие других возможностей. Можно попробовать грязный хак вроде "все параметры функции или типа, тип которых не указан, имеют тип Type", но идея так себе.


VD>Дык в C#/Nemerle параметры типов как раз задаются явно. Первые квадратные скобки — это как раз их описание. Считай тот же forall. А уже внутри описания параметров и возвращаемого значения — это аргументы. Просто область видимости.


Это работает ровно потому, что в C#/Nemerle нет зависимых типов и все параметры типов -- типы, а не выражения.

AR>>В "инвариантах" может быть далеко не только равенство, а любые условия. Так что скорее инвариант должен выглядеть как
l1.Length == l2.Length, l1.Length == result.Length
Уже хуже.


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


AR>>Неявные параметры для типов -- это понятно непосвящённым?


VD>Мне кажется это будет проще объяснить. В прочем — это не более чем идея не претендующая на истину.


AR>>Почему неявный параметр -- именно длина, а не (например) первый элемент списка?


VD>Потому что в этом есть смысл для данной структуры данных.


А для какой-то другой функции нам легко могут понадобиться списки, параметризованные не по длине.

AR>>Мне не хотелось бы каждый раз раз лезть в определение списка и выяснять, какие свойства можно использовать в инвариантах, а какие -- нет.


VD>А мне вообще не хотелось бы никуда лезть, и не хотелось бы разбираться в трехметровом описании типа. Мне хотелось бы, чтобы в случае кода я ошибаюсь, чтобы компилятор бил меня по рукам.


"list(A : Type, n : int) = variant
| [] : list(A, 0)
| :: (x : A, l : list(A, n)) : list(A, n+1)"

далеко не трёхметровое описание

AR>>Давай ещё сделаем A и B неявными:

AR>>zip(l1 : list, l2 : list) : list
AR>> types invariant l1.Length == l2.Length, l1.Length == result.Length,
AR>> value.Type == l1.Type * l2.Type
AR>>{
AR>> ...
AR>>}
AR>>[/c#]
AR>>По-моему, это не стало ни понятнее, ни короче. Точно так же вариант с длиной как неявным параметром мне не нравится.

VD>Какие-то они не очень не явные.

VD>Ты просто перенес описание типов в свойство (или поле).

Так ты сделал то же самое с длиной.

VD>>>Ну, так дава начнем с объяснения того как статические проверки будут работать для динамически получаемых данных.

VD>>>Скажем есть у нас функция возвращающая список введенных пользователем чисел:
VD>>>
GetData[int, n : int]() : list[int, n]


AR>>Эта функция обещает вернуть список любой нужной длины.


VD>То есть параметр n я должен задать явно или он может быть выведен из сигнатуры той функции коду передается результат этой?

VD>ОК.

Так же, как и любой другой параметр функции.

AR>>Функция, которая возвращает список некоторой неизвестной длины, может иметь тип

AR>>
GetData() : (n : int) * list(int, n)


VD>Т.е. возвращать длину в кортеже и потом нужно матчить это дело, чтобы понять, что к чему?


Да.

AR>>либо использовать старый тип для списков произвольной длины (который, естественно, никуда не денется от расширения системы типов).


VD>И они не будут совместимы и мы опять будем вынуждены матчить (т.е. делать тонны проверок) и преобразовывать типы явно?


Зачем тонны?

AR>>А для этого нужно решить, что считать рабочим вариантом. Как эта функция должна себя вести, если списки имеют разную длину?

AR>>[q]
AR>>Main() : void
AR>>{
AR>> def (_,data1) = GetData();
AR>> def (_,data2) = GetData();
AR>> def res = Zip1(GetData(), GetData());
AR>> WriteLine(res);
AR>>}
AR>>[/c#]

VD>А зачем тут строки:

AR>> def (_,data1) = GetData();
AR>> def (_,data2) = GetData();
VD>?

GetData возвращает кортежи из длин и списков, как мы уже знаем. Мы их матчим, помещаем первый список в data1, а второй в data2, длину отбрасываем (раз она нас не интересует).
Ошибка в следующей строчке: должно быть
def res = Zip1(data1, data2);
Re[9]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 08.07.09 08:38
Оценка:
T>>Делаем проверку на равенство. Если равны, то можно zip. Не равны, отрежем кого. Или приклеим кому.

VD>То есть верифицировать весь код и заставлять писать все проверки?


Если тебя интересует правильность работы программы — да.

VD>А не офигеш ли это делать?


Нет.

VD>Исключения придумали для того, чтобы когда пишешь логику по меньше думать о редких граничных условиях. Если проверять все, то код может разбухнуть очень и очень сильно.


Монада Maybe, монада Error. Два типа исключений.

VD>Кто-нибудь проводил сравнение трудозатрат вызванных тестированием и вызванных тотальными проверками всех нюансов?


Вместе с трудозатратами, связанными с поздним обнаружением ошибок — вряд ли.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[15]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 08.07.09 08:46
Оценка:
Здравствуйте, VladD2, Вы писали:

L>>Система типов должна описывать ограничения. Ограничения очень хорошо описываются выражениями, над выражениями обычно производятся вычисления.

VD>С этим я согласен. Но, я о другом говорю, о том, что вычисления над типами не должны приводить к другим эффектам. К генерации кода как в шаблонах С++. Или к посылке мыла на почтовый ящик.

А, нет, такого нет. Ну, вот, например, нам надо декларировать, что конкатенация списков будет иметь длину, равную сумме длин списков-аргументов. Для этого нужно провести вычисление — сложение. В таких пределах.

L>>Что касается 1-2 процентов программистов — почему тебя это так волнует? Ты же себе инструмент должен подобрать, а не 98-99% программистов.

VD>Меня не интересуют задачи которые можно решить силами одного, пусть даже очень одаренного программиста, так как они не выходят за рамки олимпиадных задачек. Меня интересуют большие проекты на которые нужно тратить много десятков человеко-лет даже не смотря на уровень человека и используемого им инструмента. А это требует того, чтобы код понимали хотя бы не бездарные программисты.
VD>Потом это только ты можешь писать код в vim-е. А мне нужен рефакторин, система управления проектами, подсветка не только синтаксиса, но и интеллектуальная подсветка типов, хороший отладчик и т.д. и т.п. А это все банально не сделают для языка который понимают пара сотня человек в мире.

Понятно, спасибо за разъяснения, я немного другого мнения, бьём задачи по кускам, есть какие то общие соглашения, остальное — на произвол разработчику. Т.е. из большого проекта опять таки получаем небольшие задачи и их уже решаем своими средствами. Впрочем, это оффтопик.
Re[12]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.07.09 20:32
Оценка:
Здравствуйте, Alexey Romanov, Вы писали:

AR>Потому что для зависимых типов разница между параметрами типов и функций несущественна. У zip не 3 генерик-параметра и 2 аргумента функции, а просто 5 аргументов.


Э... погоди.
1. Что это дает?
2. Все эти параметры должны обрабатываться в рантайме? Не приведет ли это к непроизводительным расходам вычислительных мощностей?
3. Почему нельзя по старинке иметь параметры типов и обычные параметры?

AR>Но чтобы при использовании (а не объявлении) функций избежать громоздкости, нужно ввести неявные аргументы. A, B, и len мы всегда можем извлечь из типа l1 и l2, поэтому они могут передаваться неявно.


+1

AR>Какое-то обозначение для неявных параметров нам нужно, а C#/Nemerle как раз позволяет вывод генерик-параметров (иногда).


Что значит "(иногда)"?

VD>>Так что в квадратных скобках у меня как раз объявлены переменные типов.


AR>len -- не переменная типа по-любому.


Ну, а как ее назвать тогда? Она же входит в описание типа. Так?

VD>>Дык в C#/Nemerle параметры типов как раз задаются явно. Первые квадратные скобки — это как раз их описание. Считай тот же forall. А уже внутри описания параметров и возвращаемого значения — это аргументы. Просто область видимости.


AR>Это работает ровно потому, что в C#/Nemerle нет зависимых типов и все параметры типов -- типы, а не выражения.


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

AR>>>Почему неявный параметр -- именно длина, а не (например) первый элемент списка?

VD>>Потому что в этом есть смысл для данной структуры данных.
AR>А для какой-то другой функции нам легко могут понадобиться списки, параметризованные не по длине.

Понадобятся — создадим. Но это будет другая структура данных.

VD>>А мне вообще не хотелось бы никуда лезть, и не хотелось бы разбираться в трехметровом описании типа. Мне хотелось бы, чтобы в случае кода я ошибаюсь, чтобы компилятор бил меня по рукам.


AR>"list(A : Type, n : int) = variant

AR> | [] : list(A, 0)
AR> | :: (x : A, l : list(A, n)) : list(A, n+1)"

AR>далеко не трёхметровое описание


Согласен. Но по суи "A : Type, n : int" — это и есть расширенное описание параметров типов.
В немерловом варианте можно было бы записать его как-то так:
variant list[T, n : uint]
{
  | nil[_, 0]
  | cons[_, _] { head : T; tail : list[T, n - 1]; }
}



VD>>Какие-то они не очень не явные.

VD>>Ты просто перенес описание типов в свойство (или поле).

AR>Так ты сделал то же самое с длиной.


Длинна по логике структуры данных — это свойство.

VD>>И они не будут совместимы и мы опять будем вынуждены матчить (т.е. делать тонны проверок) и преобразовывать типы явно?


AR>Зачем тонны?


Не "зачем?", а "почему?". По жизни .
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[13]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 10.07.09 21:51
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Alexey Romanov, Вы писали:


AR>>Потому что для зависимых типов разница между параметрами типов и функций несущественна. У zip не 3 генерик-параметра и 2 аргумента функции, а просто 5 аргументов.


VD>Э... погоди.

VD>1. Что это дает?

Гибкость.

VD>2. Все эти параметры должны обрабатываться в рантайме? Не приведет ли это к непроизводительным расходам вычислительных мощностей?


Нет.

Если нет операции casetype (сделать вычисление пришедшего аргумента-типа), то набор операций ограничен и типы будут устранены чем-то вроде constant propagation.

VD>3. Почему нельзя по старинке иметь параметры типов и обычные параметры?


В определённый момент может потребоваться параметр-индекс. Например, функция average вполне может рассчитывать на то, что ей доступна длина списка.

Кстати, в этом случае длина списка будет вычислена и не будет устранена.

VD>>>Так что в квадратных скобках у меня как раз объявлены переменные типов.

AR>>len -- не переменная типа по-любому.
VD>Ну, а как ее назвать тогда? Она же входит в описание типа. Так?

Индекс типа. Вполне официальное название.

VD>>>И они не будут совместимы и мы опять будем вынуждены матчить (т.е. делать тонны проверок) и преобразовывать типы явно?

AR>>Зачем тонны?
VD>Не "зачем?", а "почему?". По жизни .

Я как-то тебе сказал, что в этом случае работают монады. Не хочешь всё время проверять, работай внутри монады с исключениями.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[13]: [Зависимые типы] Объясните на пальцах.
От: Alexey Romanov  
Дата: 11.07.09 23:43
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, Alexey Romanov, Вы писали:


AR>>Потому что для зависимых типов разница между параметрами типов и функций несущественна. У zip не 3 генерик-параметра и 2 аргумента функции, а просто 5 аргументов.


VD>Э... погоди.

VD>1. Что это дает?
А что даёт различие между параметрами типов и аргументами функции? См. пункт 3.
VD>2. Все эти параметры должны обрабатываться в рантайме? Не приведет ли это к непроизводительным расходам вычислительных мощностей?
Нет. Опять-таки в зависимости от силы нашей системы типов. Но вообще говоря, при ограниченном языке операций над типами, можно всю работу с ними оставить на компайл-тайм.
VD>3. Почему нельзя по старинке иметь параметры типов и обычные параметры?
По старинке типы могли зависеть только от типов, причём весьма ограниченным образом.

AR>>Какое-то обозначение для неявных параметров нам нужно, а C#/Nemerle как раз позволяет вывод генерик-параметров (иногда).

VD>Что значит "(иногда)"?
В C# невозможно вывести генерик-параметры конструкторов и те, которые появляются только в возвращаемых типах. Не помню, как с этим в Nemerle?

VD>>>Так что в квадратных скобках у меня как раз объявлены переменные типов.

AR>>len -- не переменная типа по-любому.
VD>Ну, а как ее назвать тогда? Она же входит в описание типа. Так?
Параметр или индекс типа.

VD>>>Дык в C#/Nemerle параметры типов как раз задаются явно. Первые квадратные скобки — это как раз их описание. Считай тот же forall. А уже внутри описания параметров и возвращаемого значения — это аргументы. Просто область видимости.

AR>>Это работает ровно потому, что в C#/Nemerle нет зависимых типов и все параметры типов -- типы, а не выражения.
VD>Ну, параметр типа фактически преобразуется в переменную типа (когда с ней работают). Думаю, что не трудно будет добавить в переменную типа поле содержащее значение или выражение (выражение ведь, тоже в каком-то смысле значение, это или функция или класс с методами...).
1. Генерик-параметр в .Net -- далеко не то же, что поле класса Type. В том числе, когда с ним работают.
2. 3 -- это функция или класс с методами?

AR>>>>Почему неявный параметр -- именно длина, а не (например) первый элемент списка?

VD>>>Потому что в этом есть смысл для данной структуры данных.
AR>>А для какой-то другой функции нам легко могут понадобиться списки, параметризованные не по длине.
VD>Понадобятся — создадим. Но это будет другая структура данных.
Но как их отличить, если эти параметры--неявные? Если у нас может быть один list[A], неявно параметризованный по длине, а другой--по сумме элементов?

VD>>>А мне вообще не хотелось бы никуда лезть, и не хотелось бы разбираться в трехметровом описании типа. Мне хотелось бы, чтобы в случае кода я ошибаюсь, чтобы компилятор бил меня по рукам.


AR>>"list(A : Type, n : int) = variant

AR>> | [] : list(A, 0)
AR>> | :: (x : A, l : list(A, n)) : list(A, n+1)"

AR>>далеко не трёхметровое описание


VD>Согласен. Но по суи "A : Type, n : int" — это и есть расширенное описание параметров типов.

VD>В немерловом варианте можно было бы записать его как-то так:
VD>
VD>variant list[T, n : uint]
VD>{
VD>  | nil[_, 0]
VD>  | cons[_, _] { head : T; tail : list[T, n - 1]; }
VD>}
VD>

Так почему здесь T -- тип? Я уже сказал, что "любой параметр типа по умолчанию -- тип" кажется мне грязным хаком.

VD>>>Какие-то они не очень не явные.

VD>>>Ты просто перенес описание типов в свойство (или поле).
AR>>Так ты сделал то же самое с длиной.
VD>Длинна по логике структуры данных — это свойство.
Если длина -- параметр типа, то делать её ещё и свойством -- всё равно, что иметь для списков в C# свойство IsList
Re[7]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 12.07.09 07:54
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Дык переменные типы можно описывать в скобках как в С++, Яве и дотнете. Выкидываем "forall{A B n} ->" и добавляем "zip<A, B, n>".


Я пока не совсем разобрался, но на первый взгляд в ATS более простые описания http://www.ats-lang.org/
Re[9]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 12.07.09 08:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Исключения придумали для того, чтобы когда пишешь логику по меньше думать о редких граничных условиях. Если проверять все, то код может разбухнуть очень и очень сильно.


VD>Кто-нибудь проводил сравнение трудозатрат вызванных тестированием и вызванных тотальными проверками всех нюансов?


Если судить по размеру кода то тот же ATS приогрывает обоим прородителям, ML образным (OCaml) очень сильно:

http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=ocaml&amp;box=1

Сиобразным (притом в лице низкоуровневого Си) практически вдвое:

http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=gcc&amp;box=1
Re[8]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 12.07.09 12:22
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, VladD2, Вы писали:


VD>>Дык переменные типы можно описывать в скобках как в С++, Яве и дотнете. Выкидываем "forall{A B n} ->" и добавляем "zip<A, B, n>".


FR>Я пока не совсем разобрался, но на первый взгляд в ATS более простые описания http://www.ats-lang.org/


ATS это продолжение DML. Который содержал "зависимые типы" в виде системы ограничений на целые параметры. От DML он недалеко ушёл.

Система с ограничениями вместо теории типов Мартина-Лёфа практична, но мало интересна.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[10]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 12.07.09 12:22
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, VladD2, Вы писали:


VD>>Исключения придумали для того, чтобы когда пишешь логику по меньше думать о редких граничных условиях. Если проверять все, то код может разбухнуть очень и очень сильно.


VD>>Кто-нибудь проводил сравнение трудозатрат вызванных тестированием и вызванных тотальными проверками всех нюансов?


FR>Если судить по размеру кода то тот же ATS приогрывает обоим прородителям, ML образным (OCaml) очень сильно:


FR>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=ocaml&amp;box=1


FR>Сиобразным (притом в лице низкоуровневого Си) практически вдвое:


FR>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=gcc&amp;box=1


Сравни количество человеко-времени. ATS пишет всего один человек и не так давно.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[11]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 12.07.09 13:21
Оценка:
Здравствуйте, thesz, Вы писали:

T>Сравни количество человеко-времени. ATS пишет всего один человек и не так давно.


Не понял
Re[12]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 12.07.09 17:45
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, thesz, Вы писали:


T>>Сравни количество человеко-времени. ATS пишет всего один человек и не так давно.


FR>Не понял


Оптимизатор так себе, поскольку толком не отработан, сами реализации тоже пишет всего один человек, а уже всего вдвое хуже C.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[14]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.07.09 19:02
Оценка:
Здравствуйте, Alexey Romanov, Вы писали:

AR>А что даёт различие между параметрами типов и аргументами функции? См. пункт 3.


Возможность вычислить типы во время компиляции (не тратить на них время в рантайме).

VD>>3. Почему нельзя по старинке иметь параметры типов и обычные параметры?

AR>По старинке типы могли зависеть только от типов, причём весьма ограниченным образом.

А чему это противоречит?

AR>В C# невозможно вывести генерик-параметры конструкторов и те, которые появляются только в возвращаемых типах. Не помню, как с этим в Nemerle?


Никаких проблем.

VD>>>>Так что в квадратных скобках у меня как раз объявлены переменные типов.

AR>>>len -- не переменная типа по-любому.
VD>>Ну, а как ее назвать тогда? Она же входит в описание типа. Так?
AR>Параметр или индекс типа.

Может тогда "свойство типа"?

Логично, что если мы описываем зависимости, то это зависимости между свойствами.

VD>>Ну, параметр типа фактически преобразуется в переменную типа (когда с ней работают). Думаю, что не трудно будет добавить в переменную типа поле содержащее значение или выражение (выражение ведь, тоже в каком-то смысле значение, это или функция или класс с методами...).

AR>1. Генерик-параметр в .Net -- далеко не то же, что поле класса Type. В том числе, когда с ним работают.

Дык я говорю о внутреннем представлении типа в языке.

AR>2. 3 -- это функция или класс с методами?


Не понял вопроса. Что за "3"?

AR>Но как их отличить, если эти параметры--неявные? Если у нас может быть один list[A], неявно параметризованный по длине, а другой--по сумме элементов?


У них имена разные будут.

VD>>В немерловом варианте можно было бы записать его как-то так:

VD>>
VD>>variant list[T, n : uint]
VD>>{
VD>>  | nil[_, 0]
VD>>  | cons[_, _] { head : T; tail : list[T, n - 1]; }
VD>>}
VD>>

AR>Так почему здесь T -- тип? Я уже сказал, что "любой параметр типа по умолчанию -- тип" кажется мне грязным хаком.

Потому что объявлен в списке параметров типа и при этом не указан явный скалярный тип.

VD>>Длинна по логике структуры данных — это свойство.

AR>Если длина -- параметр типа, то делать её ещё и свойством -- всё равно, что иметь для списков в C# свойство IsList

Ну, можно же иметь свойство типа которое может быть синтаксически доступно как свойство экземпляра.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 20.07.09 10:06
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, thesz, Вы писали:


T>>Оптимизатор так себе, поскольку толком не отработан, сами реализации тоже пишет всего один человек, а уже всего вдвое хуже C.


FR>А причем тут оптимизатор?

FR>Я сравнивал только размер исходников. И при этом высокуровневый ATS продул Си.

Именно поэтому я и считаю, что твоё сравнение неправильно.

Вложи в оптимизатор ATS сравнимое со вложенным в оптимизатор С количество человеко-лет, тогда можно будет сравнивать.

FR>Насчет оптимизатора, он просто попытался повторить "подвиг" автора языка D который несколько лет назад тоже ваяя язык в одиночку и вообще умудрился занять весь топ на http://shootout.alioth.debian.org/ это совершенно ничего ни говорит о быстродействии языка, это говорит только о том что можно легко подогнать язык под тесты.


Или насколько просто на нём оптимизировать программы.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[15]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 20.07.09 11:50
Оценка:
Здравствуйте, thesz, Вы писали:


T>Именно поэтому я и считаю, что твоё сравнение неправильно.


Покажи правильное по твоему.

T>Вложи в оптимизатор ATS сравнимое со вложенным в оптимизатор С количество человеко-лет, тогда можно будет сравнивать.


Опять при чем тут оптимизатор?
Сравнивался только размер исходников, ATS из-за деклараций типов получается более многословным чем си, хотя сам язык по выразительности близок к ML.

FR>>Насчет оптимизатора, он просто попытался повторить "подвиг" автора языка D который несколько лет назад тоже ваяя язык в одиночку и вообще умудрился занять весь топ на http://shootout.alioth.debian.org/ это совершенно ничего ни говорит о быстродействии языка, это говорит только о том что можно легко подогнать язык под тесты.


T>Или насколько просто на нём оптимизировать программы.


Ничего это не значит, кроме того, что возможна откровенная подгонка.
Кроме D еще несколько авторов языков занимались такой же фигней. Плюс качество многих тестов на этом ресурсе очень слабое, хотя в пследнее время есть прогресс.
Re[16]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 20.07.09 12:24
Оценка:
T>>Именно поэтому я и считаю, что твоё сравнение неправильно.
FR>Покажи правильное по твоему.

Учти время написания оптимизатора. Сколько лет ATS? Сколько лет Си?

T>>Вложи в оптимизатор ATS сравнимое со вложенным в оптимизатор С количество человеко-лет, тогда можно будет сравнивать.

FR>Опять при чем тут оптимизатор?
FR>Сравнивался только размер исходников, ATS из-за деклараций типов получается более многословным чем си, хотя сам язык по выразительности близок к ML.

Дай ссылку на тесты с ATS. Доступный мне shootout его не содержит.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[17]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 20.07.09 12:56
Оценка:
Здравствуйте, thesz, Вы писали:

T>Учти время написания оптимизатора. Сколько лет ATS? Сколько лет Си?


Опять при чем тут оптимизатор?
Тот же OCaml с никаким оптимизатором там же в одно время стоял по многим тестам на первых местах, часто опережая C++, просто нашелся человек нормально написавший тесты.

FR>>Сравнивался только размер исходников, ATS из-за деклараций типов получается более многословным чем си, хотя сам язык по выразительности близок к ML.


T>Дай ссылку на тесты с ATS. Доступный мне shootout его не содержит.


Так выше уже давал

http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=ocaml&amp;box=1
http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=gcc&amp;box=1
Re[18]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 20.07.09 13:43
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, thesz, Вы писали:


T>>Учти время написания оптимизатора. Сколько лет ATS? Сколько лет Си?

FR>Опять при чем тут оптимизатор?
FR>Тот же OCaml с никаким оптимизатором там же в одно время стоял по многим тестам на первых местах, часто опережая C++, просто нашелся человек нормально написавший тесты.

Я думаю, что надо подождать. И для ATS такой найдётся.

FR>>>Сравнивался только размер исходников, ATS из-за деклараций типов получается более многословным чем си, хотя сам язык по выразительности близок к ML.

T>>Дай ссылку на тесты с ATS. Доступный мне shootout его не содержит.
FR>Так выше уже давал
FR>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=ocaml&amp;box=1

Здесь ATS безусловно выигрывает.

FR>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=gcc&amp;box=1


Отличие в скорости незначительно (не два раза), в размере исходников значительно.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[19]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 20.07.09 13:54
Оценка:
Здравствуйте, thesz, Вы писали:


T>Я думаю, что надо подождать. И для ATS такой найдётся.


Уже нашелся, сам автор языка.


FR>>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=ocaml&amp;box=1


T>Здесь ATS безусловно выигрывает.


В три — шесть раз больший объем исходников это выигрывает

FR>>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=gcc&amp;box=1


T>Отличие в скорости незначительно (не два раза), в размере исходников значительно.


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

Мне интересна цена в выразительности которую надо платить за зависимые типы. Поэтому
все кроме объема исходников меня в этих тестах не интерсует, и по этому параметру
ATS конкретно сливает.
Re[20]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 20.07.09 19:58
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, thesz, Вы писали:


T>>Я думаю, что надо подождать. И для ATS такой найдётся.

FR>Уже нашелся, сам автор языка.

Для OCaml писал Xavier Leroy?

FR>>>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=ocaml&amp;box=1


T>>Здесь ATS безусловно выигрывает.

FR>В три — шесть раз больший объем исходников это выигрывает

Да, пропустил. Но по остальным параметрам он выигрывает.

FR>>>http://shootout.alioth.debian.org/u32/benchmark.php?test=all&amp;lang=ats&amp;lang2=gcc&amp;box=1


T>>Отличие в скорости незначительно (не два раза), в размере исходников значительно.


FR>По моему ты вообще не читаешь что тебе пишут.

FR>Я уже надцать раз тут повторил что меня не интересует быстродействие и оптимизатор,
FR>особенно на этом ресурсе, который знаменит подгонками.

Так вот, возьми и напиши что-либо реальное на обычном ЯП и на ЯП с зависимыми типами. Чего на шутаут кивать, который — о, ужас! — знаменит подгонками?

FR>Мне интересна цена в выразительности которую надо платить за зависимые типы. Поэтому

FR>все кроме объема исходников меня в этих тестах не интерсует, и по этому параметру
FR>ATS конкретно сливает.

Может, писавший решения задач шутаута ориентировался на скорость, а не на объём исходников? Может, писавший решения задач шутаута только начал использовать свой язык и не подобрал подходящих выразительных приёмов? Может, библиотека языка пока ещё слаба и в решениях находится то, что должно быть в библиотеке?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[21]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 21.07.09 03:27
Оценка:
Здравствуйте, thesz, Вы писали:

T>Для OCaml писал Xavier Leroy?


Хорош тролить

T>Так вот, возьми и напиши что-либо реальное на обычном ЯП и на ЯП с зависимыми типами. Чего на шутаут кивать, который — о, ужас! — знаменит подгонками?


ATS меня заинтересовал, но времени совсем нет
Так что жду хоть небольших примеров от евангилистов

FR>>Мне интересна цена в выразительности которую надо платить за зависимые типы. Поэтому

FR>>все кроме объема исходников меня в этих тестах не интерсует, и по этому параметру
FR>>ATS конкретно сливает.

T>Может, писавший решения задач шутаута ориентировался на скорость, а не на объём исходников? Может, писавший решения задач шутаута только начал использовать свой язык и не подобрал подходящих выразительных приёмов? Может, библиотека языка пока ещё слаба и в решениях находится то, что должно быть в библиотеке?


Угу еще наверно у него зуб болел.
Re[22]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 21.07.09 04:10
Оценка:
Здравствуйте, FR, Вы писали:

FR>Здравствуйте, thesz, Вы писали:


T>>Для OCaml писал Xavier Leroy?

FR>Хорош тролить

Тем же концом и тебя.

T>>Так вот, возьми и напиши что-либо реальное на обычном ЯП и на ЯП с зависимыми типами. Чего на шутаут кивать, который — о, ужас! — знаменит подгонками?

FR>ATS меня заинтересовал, но времени совсем нет
FR>Так что жду хоть небольших примеров от евангилистов

Сам разберёшься. Не много-то и надо.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Re[23]: [Зависимые типы] Объясните на пальцах.
От: FR  
Дата: 21.07.09 04:55
Оценка:
Здравствуйте, thesz, Вы писали:

T>Тем же концом и тебя.




T>>>Так вот, возьми и напиши что-либо реальное на обычном ЯП и на ЯП с зависимыми типами. Чего на шутаут кивать, который — о, ужас! — знаменит подгонками?

FR>>ATS меня заинтересовал, но времени совсем нет
FR>>Так что жду хоть небольших примеров от евангилистов

T>Сам разберёшься. Не много-то и надо.


Что-то в последнее время евангилисты жидкие пошли, немерлисты не ленились простыни кода выкатывали
Re[2]: [Зависимые типы] Объясните на пальцах.
От: chukichuki  
Дата: 12.08.09 07:36
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Это позволяет доказывать кучу утверждений и как следствие не писать код обработки подавляющего большинства нештатных ситуаций ибо их просто не может быть.


Как я понимаю, код обработки нештатных ситуаций никуда не девается. Просто в случае его отсутствия программа не скомпилируется. Например, прежде чем передавать произвольные списки a : Vec A n и b : Vec B m на вход нашему zip-у, необходимо чтобы компилятор увидел код в котором мы проверяем что для а и b справедливо n = m. В противном случае система вывода типов не даст скомпилировать программу. Поэтому код проверки строго говоря никуда не девается. Он остается. Просто само количество проверок может несколько оптимизироваться.
Re[4]: [Зависимые типы] Объясните на пальцах.
От: chukichuki  
Дата: 18.08.09 18:45
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Здравствуйте, chukichuki, Вы писали:


C>>Например, прежде чем передавать произвольные списки a : Vec A n и b : Vec B m на вход нашему zip-у, необходимо чтобы компилятор увидел код в котором мы проверяем что для а и b справедливо n = m.

WH>Если эти списки читаются из внешних источников то такой код необходим.
WH>Ибо при чтении данных из внешних источников мы вообще ничего не можем гарантировать по этому все приходится проверять.

WH>Если же мы говорим про списки внутри программы то у меня есть чувство что в подавляющем большинстве случаев (а может и вообще всегда) можно доказать что списки одинаковой длинны без проверок времени исполнения.


У меня есть два возражения. Во-первых в большинстве случаев как раз все промежуточные структуры данных, фигурирующие в программе, тем или иным образом зависят от данных полученных извне. В том числе и списки, в том числе и их размер. В противном случае это уже константы, а для работы с константами существуют гораздо более действенные методы.

Во-вторых, хоть я и незнаком с теоритическими основами зависимых типов, но инженерная интуиция заставляет сомневаться, что существует какой-то более менее серьезный метод доказательства, который можно легко внедрить в транслятор языка программирования, не сильно потеряв при этом в скорости компиляции. Скорее всего используется некая разновидность вывода типов, основанная на унификации термов первого порядка со специальной обработкой условий видa n == m.

Допускаю что я неправ. Было бы любопытно посмотреть на вывод типа для той же самой простейшей функции map, который по телу функции доказал бы что размер списка на входе равен размеру списка на выходе.
Re[5]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 18.08.09 19:43
Оценка:
Здравствуйте, chukichuki, Вы писали:

C>У меня есть два возражения. Во-первых в большинстве случаев как раз все промежуточные структуры данных, фигурирующие в программе, тем или иным образом зависят от данных полученных извне. В том числе и списки, в том числе и их размер. В противном случае это уже константы, а для работы с константами существуют гораздо более действенные методы.

Вот при загрузки в программу проверили что все согласовано, а дальше будет следить компилятор.
Скажем в 3D для экономии памяти и вычислительных ресурсов используют индексированные меши.
Скажем определение типа меша может быть таким:
record IndexedMesh (Vertex : Set, vertecesCount : Integer, indecesCount : Integer)
  verteces : array(Vertex, vertecesCount);
  indeces : array(LimitedInteger(0, vertecesCount), indecesCount);
end

Индексер массива принимает не абы какой Integer, а LimitedInteger(0, <размер массива>)
В данном случае мы проверяем при загрузке что все индексы попадают в диапазон 0 <= i < vertecesCount после чего можем спокойно брать индекс из массива indeces и индексировать этим индексом массив verteces без всяких проверок времени исполнения.

C>Допускаю что я неправ. Было бы любопытно посмотреть на вывод типа для той же самой простейшей функции map, который по телу функции доказал бы что размер списка на входе равен размеру списка на выходе.

Вот код на языке agda делающий то что ты хочешь
data Nat : Set where
  zero : Nat
   suc : Nat -> Nat

data Vec (A : Set) : Nat -> Set where
    [] : Vec A zero
  _::_ : {n : Nat} -> A -> Vec A n -> Vec A (suc n)

vmap : {A B : Set}{n : Nat} -> (A -> B) -> Vec A n -> Vec B n
vmap f [] = []
vmap f (x :: xs) = f x :: vmap f xs

Лично я не вижу что тут может тормозить при выводе типов.
Короче тут лучше пойти и вкурить например вот этот http://www.cs.chalmers.se/~ulfn/darcs/AFP08/LectureNotes/AgdaIntro.pdf документ хотя бы начало.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 09:55
Оценка:
Здравствуйте, chukichuki, Вы писали:

C>Допускаю что я неправ. Было бы любопытно посмотреть на вывод типа для той же самой простейшей функции map, который по телу функции доказал бы что размер списка на входе равен размеру списка на выходе.


Вывод типов и ЗТ, кажется, несовместимы.
Re[6]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 09:55
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Лично я не вижу что тут может тормозить при выводе типов.


Конечно! Потому что в твоём примере нет вывода типов
Re[7]: [Зависимые типы] Объясните на пальцах.
От: WolfHound  
Дата: 19.08.09 10:30
Оценка:
Здравствуйте, lomeo, Вы писали:

WH>>Лично я не вижу что тут может тормозить при выводе типов.

L>Конечно! Потому что в твоём примере нет вывода типов
Ну если в твоем понимании вывод типов это исключительно вывод сигнатуры функции то нету. В такой постановки вопроса и в немерле вывода типов нету.
Но если посмотреть повнимательней то ты наверное заметишь что внутри функции не указано ни одного типа.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: [Зависимые типы] Объясните на пальцах.
От: lomeo Россия http://lomeo.livejournal.com/
Дата: 19.08.09 11:47
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Ну если в твоем понимании вывод типов это исключительно вывод сигнатуры функции то нету. В такой постановки вопроса и в немерле вывода типов нету.

WH>Но если посмотреть повнимательней то ты наверное заметишь что внутри функции не указано ни одного типа.

Это уже type checker.

А то так получится, что когда я в Яве пишу выражение, то и там вывод типов работает.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.09 18:24
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Это уже type checker.


Ерунду какую-то говоришь. Проверка типов есть в любом языке не зависимо от наличия в нем вывода типов.

L>А то так получится, что когда я в Яве пишу выражение, то и там вывод типов работает.


Так оно и есть. Только он там не полный. Точнее очень ограничены. В шарпе, например, вывод типов несколько усилили в 3-ей версии, но все равно не довели его до уровня когда внутри методов не нужно указывать типы. В немерел в телах методов типы почти не приходится указывать. Собственно если глянут на аккуратно написанные программы на хаскеле, то не трудно заметить, что там тоже типы не указываются не везде, а только для внутренней реализации (тел функций и функций скрытых в модулях).

Если это закрепить на уровне самого языка, то никто не пострадает. Так что твой аргумент, на мой взгляд, надуман.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: [Зависимые типы] Объясните на пальцах.
От: VoidEx  
Дата: 19.08.09 19:42
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, lomeo, Вы писали:


L>>Это уже type checker.


VD>Ерунду какую-то говоришь. Проверка типов есть в любом языке не зависимо от наличия в нем вывода типов.


Именно, поэтому переписываю код WolfHound'а на Си++
template <class A, class B, unsigned int n>
Vec<B, n> vmap(std::function<B (A)> f, Vec<A, n> const &)
{ ... }

Где тут вывод типов?
Вот если бы сигнатуры vmap не было, то был бы вывод. А при подстановке конкретных параметров — это уже type check, как правильно заметил lomeo
Re[6]: [Зависимые типы] Объясните на пальцах.
От: VladD2 Российская Империя www.nemerle.org
Дата: 19.08.09 22:08
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Вывод типов и ЗТ, кажется, несовместимы.


Только если вести речь о выводе сигнатур глобальных функций и типов. А уровне тел функций проблем быть не должно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: [Зависимые типы] Объясните на пальцах.
От: thesz Россия http://thesz.livejournal.com
Дата: 20.08.09 16:04
Оценка:
Здравствуйте, lomeo, Вы писали:

L>Здравствуйте, WolfHound, Вы писали:


WH>>Ну если в твоем понимании вывод типов это исключительно вывод сигнатуры функции то нету. В такой постановки вопроса и в немерле вывода типов нету.

WH>>Но если посмотреть повнимательней то ты наверное заметишь что внутри функции не указано ни одного типа.

L>Это уже type checker.


L>А то так получится, что когда я в Яве пишу выражение, то и там вывод типов работает.


В Агде двунаправленная проверка. Как и в Кайенне.

Снизу вывод, сверху проверяльщик.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.