T>>class Ordered order a where
T>> mkOrder :: order -> a -> a -> (a,a)
T>>data ByField1
T>>instance Ordered ByField1 Obj
T>> mkOrder _ a b = if field1 a > field1 b then (a,b) else (b,a)
T>>
T>>Упорядоченную пару я создал, из неё можно сделать упорядоченный список похожим образом. G>Да уж... одна строка типа...
А вот дальше — одна строка, практически:
sortByField1 :: Ordered ByField1 Obj => [obj] -> SortedList ByField1 Obj
sortByField1 list = sortByOrdering list
sortByField2Rev :: Ordered ByField2Rev Obj => [obj] -> SortedList ByField2Rev Obj
sortByField2Rev list = sortByOrdering list
Ошибиться вариантов минимум.
T>>Заметь, что упорядочение у меня протягивает и доказательство тоже. То есть, достаточно создать правильное создание упорядоченного списка (пары) и сделать несколько instance Ordered, и всё со всеми заработает. Правильность кода доказана. G>ИХМО приседаний многовато. Хотя надо на реальном проекте сравнить.
Контракты получаются явные, видны невооружённым глазом, лежат рядом с реализацией.
В тех случаях, когда мне удавалось применить (я же только учусь) это очень помогало.
T>>Мы можем возложить на компилятор проверки полноты рассмотрения нами всех вариантов входных данных (http://www.haskell.org/ghc/docs/latest/html/users_guide/options-sanity.html ищи -fwarn-incomplete-patterns). G>Вне контекста pattern-matching такое рассматривать смысла нет.
Этого я не понял. Объясни, пожалуйста.
T>>>>Сравни с QuickCheck, которая вообще библиотекой выполнена. G>>>Pex выполняет анализ кода, а не тестирование случаными данными. G>>>Для тестирования случайными данными в .NET можно тоже просто библиотеку написать. T>>И как ты проверишь все возможные пути изменения состояния? G>Я — никак, а pex умеет.
Ой ли? Всех объектов всех графов?
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Здравствуйте, thesz, Вы писали:
T>>>Не уверен. У тебя несколько строк кода тестов, у меня одна строка типа. G>>Хм... например тест проверяет что функция возвращает список объектов, упорядоченных по одному из полей. G>>Как это одной строкой типа записать?
T>Хотя могу.
T>
T>instance Ordered ByField1 Obj
T> mkOrder _ a b = if field1 a > field1 b then (a,b) else (b,a)
T>
T>Упорядоченную пару я создал, из неё можно сделать упорядоченный список похожим образом.
T>Заметь, что упорядочение у меня протягивает и доказательство тоже. То есть, достаточно создать правильное создание упорядоченного списка (пары) и сделать несколько instance Ordered, и всё со всеми заработает. Правильность кода доказана.
А где проверка того, что упорядочение идет именно в том порядке, в котором это нужно для задачи? У тебя, насколько это можно понять, значения в парах сортируются в порядке убывания. А если нужно в порядке возрастания?
Unit-тест как раз проверил бы, не ошибся ли разработчик при записи field a <что-то> field b.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, FR, Вы писали:
FR>Здравствуйте, gandjustas, Вы писали:
T>>>И как ты проверишь все возможные пути изменения состояния? G>>Я — никак, а pex умеет.
FR>Комбинаторный взрыв не помешает?
Может и помешает.
Но нету необходимости проводить полный анализ. Можно кго сильно ограничит контрактами или вообще задать сценарии работы — параметризованные тесты.
Здравствуйте, thesz, Вы писали:
T>>>Мы можем возложить на компилятор проверки полноты рассмотрения нами всех вариантов входных данных (http://www.haskell.org/ghc/docs/latest/html/users_guide/options-sanity.html ищи -fwarn-incomplete-patterns). G>>Вне контекста pattern-matching такое рассматривать смысла нет.
T>Этого я не понял. Объясни, пожалуйста.
int func(int a)
{
if(a = 1) return 0;
return 1;
}
Если последний return не написать то даже компилироваться не будет.
Это только особенность записи функций в хаскеле что можно забыть сопоставить выходные значения некоторому набору входных значений.
T>>>>>Сравни с QuickCheck, которая вообще библиотекой выполнена. G>>>>Pex выполняет анализ кода, а не тестирование случаными данными. G>>>>Для тестирования случайными данными в .NET можно тоже просто библиотеку написать. T>>>И как ты проверишь все возможные пути изменения состояния? G>>Я — никак, а pex умеет.
T>Ой ли? Всех объектов всех графов?
Не знаю, я этого зверька пока только в ограниченных условиях гонял.
T>>Заметь, что упорядочение у меня протягивает и доказательство тоже. То есть, достаточно создать правильное создание упорядоченного списка (пары) и сделать несколько instance Ordered, и всё со всеми заработает. Правильность кода доказана.
E>А где проверка того, что упорядочение идет именно в том порядке, в котором это нужно для задачи? У тебя, насколько это можно понять, значения в парах сортируются в порядке убывания. А если нужно в порядке возрастания?
E>Unit-тест как раз проверил бы, не ошибся ли разработчик при записи field a <что-то> field b.
В полноценных зависимых типах индексом могут быть и функции.
В этом случае всё выглядело бы так:
data OrderedPair : (a : Set) -> {b : Set} ->
(map : a -> b) -> (less : b -> b -> Bool) where
OrderPair : {a b : Set} -> {map : a -> b} -> {less : b -> b -> Bool} ->
(x y : a) -> {less (map x) (map y) = True} -> OrderedPair a b map less
byField1 : {a : Set} -> a -> a -> OrderedPair a getField1 (_<_)
byField1 a b | getField1 a < getField1 b
byField1 a b True = OrderPair a b
byField1 a b False = OrderPair b a
byField1Rev : {a : Set} -> a -> a -> OrderedPair a getField1 (_>_)
byField1Rev ...
byField1 иначе не напишешь. Компилятор будет настаивать.
Это хорошее решение?
В Хаскеле же доступно вот то, что я показал выше. И общее движение в сторону полных зависимых типов.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
T>>>>Мы можем возложить на компилятор проверки полноты рассмотрения нами всех вариантов входных данных (http://www.haskell.org/ghc/docs/latest/html/users_guide/options-sanity.html ищи -fwarn-incomplete-patterns). G>>>Вне контекста pattern-matching такое рассматривать смысла нет. T>>Этого я не понял. Объясни, пожалуйста. G>
G>Если последний return не написать то даже компилироваться не будет. G>Это только особенность записи функций в хаскеле что можно забыть сопоставить выходные значения некоторому набору входных значений.
Что будет, если не int, а дерево и проверка посложней и вариантов побольше? Что будет, если структура дерева поменялась, и появился новый вариант?
Компилятор Хаскеля мне об этом скажет.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, thesz, Вы писали:
T>>>>Мы можем возложить на компилятор проверки полноты рассмотрения нами всех вариантов входных данных (http://www.haskell.org/ghc/docs/latest/html/users_guide/options-sanity.html ищи -fwarn-incomplete-patterns). G>>>Вне контекста pattern-matching такое рассматривать смысла нет.
T>>Этого я не понял. Объясни, пожалуйста. G>
G>Если последний return не написать то даже компилироваться не будет. G>Это только особенность записи функций в хаскеле что можно забыть сопоставить выходные значения некоторому набору входных значений.
Это не особенность записи функций хаскеля, это свойство паттерн-матчинга.
Ближайшим (правда ооочень фиговым) шарповским аналогом ПМ по-моему является switch, но вот что-то я не припомню проверки полноты его компилятором
Можно ещё и про "проваливающиеся" case вспомнить...
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, eao197, Вы писали:
E>>Вот, например, описание агента. Более-менее сложного.
V>Жень, тебе надо компилятор из некоего DSL в целевой С++ делать, а то как-то действительно "более-менее сложно" получается.
DSL тут не принципиален. Будет выглядеть чуть лучше, и только. Его фреймворк вынуждает программиста к разворачиванию всех сценариев взаимодействия агентов в явно записанные конечные автоматы, и в этом корень проблемы. Даже простые сценарии будут выглядеть очень сложно на ровном месте.
Здравствуйте, thesz, Вы писали:
E>>А где проверка того, что упорядочение идет именно в том порядке, в котором это нужно для задачи? У тебя, насколько это можно понять, значения в парах сортируются в порядке убывания. А если нужно в порядке возрастания?
E>>Unit-тест как раз проверил бы, не ошибся ли разработчик при записи field a <что-то> field b.
T>В полноценных зависимых типах индексом могут быть и функции.
T>В этом случае всё выглядело бы так: T>
T>byField1 : {a : Set} -> a -> a -> OrderedPair a getField1 (_<_)
T>
T>byField1 иначе не напишешь. Компилятор будет настаивать.
T>Это хорошее решение?
Если я правильно понял, то теперь просто место потенциальной ошибки сместилось в запись "...getField1 (_<_)". Но что, если программист невнимательно прочитал спецификацию или же случайно написал (_<_) вместо (_>_). Кто это будет проверять?
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, gandjustas, Вы писали:
G>>>>Данная "декларативность" его имхо затрудняет. G>>>Данная декларативность не влияет на наблюдаемое поведение.
G>>Она влияет на поведение программы.
G>Как?
Если оно не никак не влиет на поведение программы, то что может заставить программиста писать asynchronous? Я задал вопрос, чем это лучше явного употребления фьючерса. Если это на самом деле работает как фьючерс, то оно влияет на поведение программы, как фьючерс, вставленный в автоматическом режиме. Ты на вопрос не ответил ("декларативностью" — это не ответ). Если оно работает как-то по другому, и я неправильно понимаю — так объясни мне, как оно работает. Мне то ты зачем этот вопрос задаешь?
Непонятен вопрос — попроси пояснений. Не знаешь — скажи не знаю. Не хочешь отвечать — не отвечай, у нас свободная страна. Тока не надо задавать бессмысленные вопросы мне, уводя дискуссию в сторону. Мне совершенно не интересно пытаться тебя переспорить, есть дела поважнее.
Здравствуйте, eao197, Вы писали:
E>Если я правильно понял, то теперь просто место потенциальной ошибки сместилось в запись "...getField1 (_<_)". Но что, если программист невнимательно прочитал спецификацию или же случайно написал (_<_) вместо (_>_). Кто это будет проверять?
Место ошибки не сместилось, мест, где может быть ошибка, стало ровно одно. Написать (<) вместо (>) — это постараться надо. А написать неправильную сортировку — раз плюнуть.
Ты ещё скажи "а что, если юнит-тест написали неверно и он проверяет не то, и в документации опечатались".
Здравствуйте, gandjustas, Вы писали:
G>int func(int a) G>{ G> if(a = 1) return 0; G> return 1; G>} G>[/ccode] G>Если последний return не написать то даже компилироваться не будет.
Во-первых, в Си++ будет. Но, видимо, речь не о нём.
Возьми вместо int какой-нибудь enum. Теперь добавь в enum два новых значения.
Вуаля! Никакого предупреждения о том, что обрабатывается не всё, потому что хоть в switch надо default вставить, хоть в конце функции.
Здравствуйте, VoidEx, Вы писали:
E>>Если я правильно понял, то теперь просто место потенциальной ошибки сместилось в запись "...getField1 (_<_)". Но что, если программист невнимательно прочитал спецификацию или же случайно написал (_<_) вместо (_>_). Кто это будет проверять? VE>Место ошибки не сместилось, мест, где может быть ошибка, стало ровно одно. Написать (<) вместо (>) — это постараться надо.
Не знаю, как кто, а я вот, наверное, раз в две-три недели по недосмотру пишу < вместо <=, не говоря уже о +1/-1. Опечатки в исходниках никто не отменял.
VE>А написать неправильную сортировку — раз плюнуть.
Не будем доводить до маразма -- сейчас собственную сортировку пишут либо полные валенки/ламеры, либо люди, которые хорошо понимают, зачем и почему они это делают. А вот написать неправильный предикат сравнения -- это запросто.
VE>Ты ещё скажи "а что, если юнит-тест написали неверно и он проверяет не то, и в документации опечатались".
И кстати, когда такие вещи всплывают -- это очень и очень хорошо. Ошибки есть везде, и в спецификации, и в тестах. И юнит тесты как раз позволяют подобные вещи отлавливать. Поскольку они очень быстро лишают человека веры в то, что если компилятор проглотил программу, то она правильная. Она может быть, безошибочная. И неправильная. Просто делает не то, что нужно было.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
E>>>Unit-тест как раз проверил бы, не ошибся ли разработчик при записи field a <что-то> field b. T>>В полноценных зависимых типах индексом могут быть и функции. T>>В этом случае всё выглядело бы так: T>>
T>>byField1 : {a : Set} -> a -> a -> OrderedPair a getField1 (_<_)
T>>
T>>byField1 иначе не напишешь. Компилятор будет настаивать. T>>Это хорошее решение? E>Если я правильно понял, то теперь просто место потенциальной ошибки сместилось в запись "...getField1 (_<_)". Но что, если программист невнимательно прочитал спецификацию или же случайно написал (_<_) вместо (_>_). Кто это будет проверять?
Далее у нас идёт сортировка списка объектов. Она тоже будет вынуждена нести крест getField1 (_<_) из-за использования OrderedPair. И так до того уровня, на котором это доказательство пропадает.
Если раньше мы могли ошибиться в самом методе сравнения и в алгоритме сортировки, то теперь не можем.
Нам надо тестировать только то место, где доказательство пропадает.
Я считаю, исходя из моего практического опыта, что для этого достаточно функциональных тестов.
Yours truly, Serguey Zefirov (thesz NA mail TOCHKA ru)
Здравствуйте, eao197, Вы писали:
EE>Не будем доводить до маразма
Действительно, не будем воспринимать пример буквально.
E>И кстати, когда такие вещи всплывают -- это очень и очень хорошо. Ошибки есть везде, и в спецификации, и в тестах. И юнит тесты как раз позволяют подобные вещи отлавливать. Поскольку они очень быстро лишают человека веры в то, что если компилятор проглотил программу, то она правильная. Она может быть, безошибочная. И неправильная. Просто делает не то, что нужно было.
Ну, можно, конечно, написать unit-test на функцию mkOrder
Здравствуйте, eao197, Вы писали:
E>Не знаю, как кто, а я вот, наверное, раз в две-три недели по недосмотру пишу < вместо <=, не говоря уже о +1/-1. Опечатки в исходниках никто не отменял.
От, этого, кстати, рекурсия хорошо помогает
Здравствуйте, Gaperton, Вы писали:
G>DSL тут не принципиален. Будет выглядеть чуть лучше, и только. Его фреймворк вынуждает программиста к разворачиванию всех сценариев взаимодействия агентов в явно записанные конечные автоматы, и в этом корень проблемы. Даже простые сценарии будут выглядеть очень сложно на ровном месте.
Если честно, я фиг его знает, что именно делают в прикладном коде эти агенты и какие конкретно там сценарии, за все сценарии не распишусь. Мне, например, и без агентов иногда код как автомат приходится делать, ибо природа задач бывает такова сама по себе, что разворот на C# через yield лишь усложняет или даже вынуждает использовать goto.
В общем, вот давняя картинка, попробуй здесь без goto:
Легко делается без goto на паттерне state или любой другой эмуляции автомата.
Надо вообще поспрашивать, какие задачи решают на его фреймворке. Как, кстати, обстоят дела с интеропом в Эрланге?