Re: Опциональные типы
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 21.02.17 05:59
Оценка: 3 (2) +4 :)
Здравствуйте, x-code, Вы писали:


XC>Опицональные типы (Optional, Maybe)

XC>это типы которые могут принимать все значения некоторого типа T ( Some<T> ), а также специальное значение None, означающее "отсутствие" данных вообще или нечто подобное.

XC>Несколько вопросов...


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

Optional — это вообще не тип, это конструктор типов, он же функтор. Он берет на вход произвольный тип (назовем его Т) и возвращает _другой_ тип. По такой формуле: F(T) = T + 1. Здесь + это сумма (копроизведение) типов, а 1 — специальный тип из одного значения (или любой изоморфный ему). Такое определение позволяет сразу построить много полезных комбинаторов (map, flatmap и пр.) и использовать это хозяйство с пользой, консистентно и без тех проблем, о которых предупреждяет WolfHound. Из этого определения сразу два вывода: 1) число возможных значений у F(T) на 1 больше, чем у T. 2) F(T) != T.
Соответственно, Nullable сойдет за Optional в тех случаях, когда исходный тип Т не содержит null, например, когда Т это инт или другой value-тип. А всякие NaN и прочие выделенные значения — это не Optional формально, хотя и похожи.
Re: Опциональные типы
От: Pavel Dvorkin Россия  
Дата: 21.02.17 14:54
Оценка: 13 (2) +1
Здравствуйте, x-code, Вы писали:


XC>2. Если у объекта некоторого класса имеется свое собственное, определенное программистом "недействительное" состояние, то может ли это быть то же самое что и None? Кажется что это разные вещи, по крайней мере в сравнении с "нулевой ссылкой": в случае нулевой ссылки объекта просто нет, поэтому невозможно обратиться ни к каким полям и т.д.; в случае пользовательского недействительного состояния недействительность чисто логическая, при этом память под объект есть, поля есть и к ним можно обратиться, можно перевести объект в действительное состояние вызвав какой-то метод и т.д.


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

Вот пример (правда, не с классом, а с результатом типа int, но тут вполне мог бы быть и класс)

https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#binarySearch-byte:A-byte-

Returns:
index of the search key, if it is contained in the array; otherwise, (-(insertion point) — 1).

Результат при неудачном поиске — отрицательное число. Недействительный индекс. Но этим отнюдь не исчерпывается этот результат. Если бы этот метод вернул мне null (в любой упаковке, хоть голый null, хоть Optional с null) — он был бы намного менее полезен. Да, он бы сообщил мне, что искомого в массиве нет, но сейчас то он мне не только это возвращает, но еще и говорит, куда вставить.
With best regards
Pavel Dvorkin
Re[5]: Опциональные типы
От: vdimas Россия  
Дата: 21.02.17 19:07
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Тебе не надоело позориться?


Тебя позорить не надоело.
Ты сам вызвался очередной вот этой безапелляционностью над безобидными вещами.


WH>Опять же бред написал.


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


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

V>>Просто есть специальное значение, приводимое (сравнимое) с произвольным типом — null.
WH>Это аналог Optional<T>.

Аналог, именно.
Одно "но" — значение null не надо многократно "оборачивать" для удовлетворения системы типов.


WH>У Optional<Optional<T>> ДВА различных null'а. У Optional<Optional<Optional<T>>> три.


В этом и проблема.
Потому что value type.
Я именно поэтому напомнил тебе как устроены подобные типы в ФП.


V>>Для алг. типов данных — тоже. Правда, эти типы данных всегда обрабатываются как ссылочные, даже если не ссылочные. ))

WH>Бред.

Аксиома. Попался на незнании.

В Хаскеле значения (Just a) и Nothing — исключительно ссылочные, имеют тип Maybe a (с точностью до "ссылочности").

Итого, точный аналог хаскелевского Maybe в дотнете можно было бы сделать так:
public class Optional<T> where T : struct {
    public readonly T Value;
    public Optional(T value) { Value = value };

    public static Optional<T> Nothing;
}

public static OptionalExtentions {
    public static bool HasValue<T>(this Optional<T> o) where T : struct {
        return o != Nothing;
    }
}

Где некая специальная ссылка (или просто null) означала бы Nothing.

Да, я в курсе про рассуждения насчет эффективности, но она зависит от конкретных сценариев. Когда у нас чаще всего получается Nothing и размер исходной структуры заметен, то "боксированный" вариант эффективней гораздо, бо просто передаётся null. А где Nothing случается нечасто, там заведомо Maybe не особо подходящ.


V>>Если string — это ссылочный тип, то Option<string> не имеет смысла, можно пользоваться сразу string.

WH>Не во всех языках есть null. Ибо null зло.

Почему null зло? Это аналог Optional/Maybe? Разве они зло? ))

Ну ОК, согласен, "строгая" ссылка тоже нужна:
public struct Strong<T> where T : class {
    public readonly T Value;

    public Strong(T value) {
        if(Object.ReferenceEquals(value, null))
            throw ...
        Value = value;
    }
}

Передавай затем "строгую" ссылку прямо как в Хаскеле и будешь всегда уверен, что там Just.
(одно хреново — в дотнете нельзя запретить дефолтный конструктор... зато в С++ можно, считай, что здесь лишь продемонстрировал идею)

Тут рассуждения простые — если изкаробки у нас уже есть аналог Optional/Maybe для ref-типов, то достаточно ввести обратное — строгий value-тип-обертку для ссылочных.

По аналогии, если value-типы уже являются "строгими", то для них достаточно ввести ссылочную обертку Optional.


V>>Это всё рассуждения в пользу бедных, потому что прикладная семантика может быть обслужена сугубо прикладными же полями, а не "системными". И даже должна, потому что булевских флагов, связанных со значениям, может быть более одного.

WH>Опять чистейший бред.

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

А за вот эти Optional<Optional<Optional<>>> надо отлучать от программирования пожизненно.
Не в состоянии сформулировать прикладную проблематику — свободен.


WH>>>то без этой фичи код не будет знать есть элемент или в таблице лежит None.

V>>А в общем случае достаточно интерпретировать null как "нет значения".
WH>Не достаточно.
...
WH>Если сюда засунуть тяжёлую функцию (а CachedFactory именно для таких функций и нужно) которая возвращает Option<что-что> то в твоём варианте алгоритм не сможет определить была вызвана функция или нет.

Я же говорю, отлучать за такое от программирования.

У тебя есть простейшая прикладная проблематика — "ленивый" вызов некоей тяжеловесной ф-ии.
Оформь эту прикладную проблематику явным образом по-месту или напиши один раз проблемно-ориентированный Lazy-хелпер (который так и будет называться и читаемость кода вырастет на порядки) и будет тебе счастье.

Кароч, еще не дочитав до сюда я уже знал, в чем дело:

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

Как грится, в хорошем вопросе — половина ответа.
Но ты ставишь вопросы ОЧЕНЬ плохо. Просто отвратительно.
Это твой фирменный стиль, однако — неумение сформулировать проблему.
Наверно именно поэтому ты не тянешь большие информационные ёмкости — мы это уже проходили с тобой.
И сейчас ты показал, почему именно.
Отредактировано 21.02.2017 19:25 vdimas . Предыдущая версия . Еще …
Отредактировано 21.02.2017 19:08 vdimas . Предыдущая версия .
Re[2]: Опциональные типы
От: vdimas Россия  
Дата: 21.02.17 19:14
Оценка:
Здравствуйте, meadow_meal, Вы писали:

_>Optional<Optional<ClanID>> clan;

_>В этом случае наличие значения clan означает, что информация передана клиенту, наличие значения clan.value означает, что пришел новый клан игрока, а его отсутствие — что игрок больше не состоит в клане.


За такое увольнять нафик.

Представляю все масштабы "удовольствия" от сопровождения такого кода. ))
Re[2]: Опциональные типы
От: vdimas Россия  
Дата: 21.02.17 19:21
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Из этого определения сразу два вывода: 1) число возможных значений у F(T) на 1 больше, чем у T.


Верно!
Что означает, что у F(T) несомненно ДРУГОЕ представление в памяти, т.е. памяти может потребоваться больше.

Например, в ФП языках некий Т был value-тип (ну вот так компилятор решил), а после заворачивания F(T) всегда получаем ссылочный тип. Итого, храним лишнюю ссылку вместо значения.

В принципе, если прикладной сценарий этого требует — то ОК.

Только какие проблемы повторить тоже самое с ссылочными (nullable) типами в том же дотнете или C++?
http://www.rsdn.org/forum/philosophy/6705306.1

Ситуация-то симметричная?
Re[3]: Опциональные типы
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 21.02.17 20:11
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Что означает, что у F(T) несомненно ДРУГОЕ представление в памяти, т.е. памяти может потребоваться больше.


Обычно так, но в некоторых языках бывают и исключения. Например, в Расте Box<T> и Option<Box<T>> представлены в памяти одинаково, потому что первый не может быть нулем, а второй это значение и использует в качестве None.

V>Только какие проблемы повторить тоже самое с ссылочными (nullable) типами в том же дотнете или C++?


Никаких проблем, повторяют.
Re[6]: Опциональные типы
От: WolfHound  
Дата: 21.02.17 21:39
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Потому что ты нихрена не понимаешь собеседника опять, как тогда с зависимыми типами. ))

Ты до сих пор считаешь, что в С++ есть зависимые типы?

Кстати GLR парсер который работает быстрее лексера я до сих пор жду.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: Опциональные типы
От: vdimas Россия  
Дата: 21.02.17 21:51
Оценка:
Здравствуйте, D. Mon, Вы писали:

V>>Что означает, что у F(T) несомненно ДРУГОЕ представление в памяти, т.е. памяти может потребоваться больше.

DM>Обычно так, но в некоторых языках бывают и исключения. Например, в Расте Box<T> и Option<Box<T>> представлены в памяти одинаково, потому что первый не может быть нулем, а второй это значение и использует в качестве None.

Ну, любой ссылочный тип у нас имеет T+1, потому что мы храним как значение T, так и ссылку на него.
Если в Расте Box<T> не может быть NULL, то получаем формулу T+1-1 ))

Прикольно, что я именно и предложил использовать боксирование в кач-ве трюка для Optional<T> здесь:
http://www.rsdn.org/forum/philosophy/6705306.1
потому что ссылочный класс изкаробки обладает nullable семантикой.

Ну и попутно заметил, что для ссылочных классов многократное "оборачивание" null не требуется.
Ну и симметрично там же преобразование из ссылочного "опасного" nullable в "строгую" ссылку.
"У дураков мысли сходятся, смотрю" (С)


V>>Только какие проблемы повторить тоже самое с ссылочными (nullable) типами в том же дотнете или C++?

DM>Никаких проблем, повторяют.

Да. В С++ такая идиома ничего не стоит в рантайм:
template<class T>
class NotNull {
    T * ptr_;

    static T* check(T* ptr) {
        if(ptr) return ptr;
        throw NullPointerException("ptr");          
    }

public:
    NotNull(T * ptr) : ptr_(check(ptr)) {}
    T* operator->() { 
        T* ptr = ptr_;
        __assume(ptr);
        return ptr;
    }
};

void foo(NotNull<int> x) {}
void bar(NotNull<int> x) { foo(x); }


Причем, из-за __assume оно местами работает быстрее, чем на голых указателях.
Ну и отсутствие необходимости проверок каждый раз. Проверка будет сделана лишь однажды — когда в первый раз будет сконструирован NotNull из голого указателя. Далее всё работает без проверок, распространяя гарантии "строгости" сколь угодно далеко, как в вызове foo(x) из bar.
Re[7]: Опциональные типы
От: vdimas Россия  
Дата: 21.02.17 22:24
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

V>>Потому что ты нихрена не понимаешь собеседника опять, как тогда с зависимыми типами. ))

WH>Ты до сих пор считаешь, что в С++ есть зависимые типы?

Я до сих пор считаю что ты поверхностен.

Ну и твой вопрос не имеет смысла, потому что мы уже разобрали недавно по косточкам два момента:
— уже было доказано и показано, что шаблоны С++ времени компиляции представляют из себя Тьюринг-полный ФП-язык с зависимыми типами;
— в случае покрытия специализациями шаблонов (можно частичными) ВСЕХ диапазонов термов, поведение программы в рантайм не отличается от аналогичной программы в зависимых типах; мы подробно разбирали "строго-типизированные ордера", где матрица состояний ордера была перенесена из данных в систему типов; в этом случае компилятор сам нагенерил всевозможные варианты, соответствующие использованными де-факто "клетками" такой матрицы (некоторые клетки могут быть невалидными, под них ничего не генерится); ну а трюк со "схлопыванием" шаблонного кода затем уменьшил повторы в бинарнике. Ву а ля. ))


WH>Кстати GLR парсер который работает быстрее лексера я до сих пор жду.


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

Т.е., как работает автоматный лексер по "жадному" алгоритму ты интуитивно понимаешь, ОК, но как этот алгоритм соотносится с LR(k) — понятия не имеешь.

И зачем ждать, когда уже всё есть? Парсеры в промышленных компиляторах С++ — все поголовно GLR или модифицированный LALR.
Никакие существующие в природе парсеры не работают быстрее.

Собсно, из-за необходимости на каждый CPP-файл перемалывать многие мегабайты H-файлов, парсинг в С++-компиляторах вылизан по самое небалуй. Если ты предложишь нечто кардинально быстрее работающее (хотя бы на 30%-50%) — можешь смело номинироваться на "Нобелевку по Информатике" (премию Тьюринга).
Отредактировано 21.02.2017 22:31 vdimas . Предыдущая версия .
Re[8]: Опциональные типы
От: WolfHound  
Дата: 21.02.17 22:50
Оценка:
Здравствуйте, vdimas, Вы писали:

V>- уже было доказано и показано, что шаблоны С++ времени компиляции представляют из себя Тьюринг-полный ФП-язык с зависимыми типами;

Садись два.

V>- в случае покрытия специализациями шаблонов (можно частичными) ВСЕХ диапазонов термов,

Покрой шаблонами целое неограниченного размера.
Как вот в этом коде Dafny доказательство сортировки выбором.
Автор: WolfHound
Дата: 29.04.16

Там все int от минус бесконечности до плюс бесконечности.
И сортировка доказана для всех массивов размером от нуля до бесконечности.
Тут ключевое слово БЕСКОНЕЧНОСТЬ.
Для зависимых типов бесконечность проблемой не является.
Когда потратишь бесконечное количество памяти и времени генерируя специализации на С++ возвращайся.
Но только смотри чтобы не раньше. Мне надоело твой бред разбирать.

V>Обещано было "со сравнимой с лексером скоростью на большинстве цепочек".

Код в студию. Ты же говоришь, что всё давно есть.
Хватит трепаться покажи код.
Мой код доступен всем. От тебя только бла-бла-бла.

V>Собсно, из-за необходимости на каждый CPP-файл перемалывать многие мегабайты H-файлов, парсинг в С++-компиляторах вылизан по самое небалуй. Если ты предложишь нечто кардинально быстрее работающее (хотя бы на 30%-50%) — можешь смело номинироваться на "Нобелевку по Информатике" (премию Тьюринга).

В С++ не парсер тормозит. Даже если бы он был в 10 раз медленней на времени компиляции это бы сказалось не сильно.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[9]: Опциональные типы
От: vdimas Россия  
Дата: 22.02.17 00:20
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

V>>- уже было доказано и показано, что шаблоны С++ времени компиляции представляют из себя Тьюринг-полный ФП-язык с зависимыми типами;

WH>Садись два.

Т.е. ты и этого не знал?
Это давно было обосновано научно с т.з. теории типов.
Или ты не понимаешь фразы "Тьюринг-полный язык времени компиляции?"


V>>- в случае покрытия специализациями шаблонов (можно частичными) ВСЕХ диапазонов термов,

WH>Покрой шаблонами целое неограниченного размера.

Ну вот я со звуком много работал. Там идёт работа с пачками отсчетов вполне конечного размера.


WH>Как вот в этом коде Dafny доказательство сортировки выбором.
Автор: WolfHound
Дата: 29.04.16

WH>Там все int от минус бесконечности до плюс бесконечности.

Ну, когда-то у шаблонов С++ в 90-е года было ограничение вложенности 256.
Недавно я испытывал — несколько тысяч легко.
Я думаю, что написать для compile-time аналогичную программу, покрывающую short, можно.

Зависимые типы времени компиляции представляются на шаблонах С++ так же как в Хаскеле — через идиому succ(succ(succ(..., т.е. нас ограничивает лишь максимальная вложенность шаблонов.


WH>И сортировка доказана для всех массивов размером от нуля до бесконечности.

WH>Тут ключевое слово БЕСКОНЕЧНОСТЬ.
WH>Для зависимых типов бесконечность проблемой не является.

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


WH>Когда потратишь бесконечное количество памяти и времени генерируя специализации на С++ возвращайся.


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


WH>Но только смотри чтобы не раньше. Мне надоело твой бред разбирать.


Твоё "бред" — это от неумения вести споры, от неумения удержаться от соблазна приписать оппоненту удобное тебе видение и ну давай его разбивать в пух и прах.
За последние 12 лет так и не повзрослел.


V>>Обещано было "со сравнимой с лексером скоростью на большинстве цепочек".

WH>Код в студию. Ты же говоришь, что всё давно есть.
WH>Хватит трепаться покажи код.
WH>Мой код доступен всем. От тебя только бла-бла-бла.

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


V>>Собсно, из-за необходимости на каждый CPP-файл перемалывать многие мегабайты H-файлов, парсинг в С++-компиляторах вылизан по самое небалуй. Если ты предложишь нечто кардинально быстрее работающее (хотя бы на 30%-50%) — можешь смело номинироваться на "Нобелевку по Информатике" (премию Тьюринга).

WH>В С++ не парсер тормозит.

Зависит от.
В любом случае утверждалось, что в промышленных современных компиляторах С++ самые быстрые парсеры на сегодня. Медицинский факт.


WH>Даже если бы он был в 10 раз медленней на времени компиляции это бы сказалось не сильно.


Это только в режиме оптимизации — С++ компиляторы сегодня по кач-ву оптимзаций рвут всех как тузики грелку. ))

А без оптимизации если, то скорость компиляции, по современным реалиям подключения просто бесконечного числа хидеров на КАЖДЫЙ cpp-файл, зависит от скорости парсинга напрямую.

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

Мы ведь парсинг обсуждаем, верно? Не лексический анализ, а именно построение AST?

Просто, никакое поделие ни на каком на дотнете не построит сегодня AST с нужной скоростью. В дотнете банально оператор new не умеет с такой скоростью работать, какая там требуется. Мои самописные страничные и пул-аллокаторы умудряются работать в несколько раз быстрее дотнетного new. А на освобождение многих многих миллионов объектов вообще зачастую ни такта не тратится — на то они и региональные аллокаторы.

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

Это я уже молчу о банальной беготне табличного парсера или лексера по его таблице состояний. Самый вылизанный дотнетный код бегает по таблице состояний почти в 2 раза медленнее. Это как?
Re[10]: Опциональные типы
От: WolfHound  
Дата: 22.02.17 01:29
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Т.е. ты и этого не знал?

V>Это давно было обосновано научно с т.з. теории типов.
Что обосновано? Зависимые типы? В каком месте?

V>Или ты не понимаешь фразы "Тьюринг-полный язык времени компиляции?"

Я это сам доказывал.
Доказательство полноты.
Автор: WolfHound
Дата: 06.02.12


V>>>- в случае покрытия специализациями шаблонов (можно частичными) ВСЕХ диапазонов термов,

WH>>Покрой шаблонами целое неограниченного размера.
V>Ну вот я со звуком много работал. Там идёт работа с пачками отсчетов вполне конечного размера.
Как эти предложения вообще связаны?
Ты вообще можешь связно думать? Или у тебя в голове работает рандом, который скачет куда попало.

V>Зависимые типы времени компиляции представляются на шаблонах С++ так же как в Хаскеле — через идиому succ(succ(succ(..., т.е. нас ограничивает лишь максимальная вложенность шаблонов.

Ох. Ни в С++ ни в хаскеле зависимых типов нет.
И про то что константы в шаблонах С++ выражаются через succ(succ(succ( я тебе рассказал.
До этого ты говорил, что, если в шаблон можно воткнуть целое значит в С++ есть зависимые типы.

WH>>И сортировка доказана для всех массивов размером от нуля до бесконечности.

WH>>Тут ключевое слово БЕСКОНЕЧНОСТЬ.
WH>>Для зависимых типов бесконечность проблемой не является.
V>Это зависит от реализации.
Не от реализации, а от математики.
Зависимый тип — это такой тип, который зависит от значений времени исполнения. А их вполне может быть бесконечное множество.

V>Мало ли где чей код доступен?

V>Твой код для чего-то серьезного, увы, не интересен и не подходящ.
V>Потому что ты выбрал не ту технологию.
Так ты свой покажи.
Я очень хочу посмотреть на правильный код, написанный на правильной технологии.
Я давно хочу посмотреть на генератор парсеров который генерирует GLR парсер и работает быстрее лексера.
Я очень хочу увидеть это чудо.
Или ты таки трепло?

V>Просто, никакое поделие ни на каком на дотнете не построит сегодня AST с нужной скоростью.

Что ты к .НЕТ прицепился. Я знаю, что он тормозит. Не надо мне это говорить.
Всё что я хочу это посмотреть на GLR парсер который работает быстрее лексера.
И мне всё равно на чем он написан.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: Опциональные типы
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 22.02.17 05:23
Оценка:
Здравствуйте, vdimas, Вы писали:

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


V>>>Что означает, что у F(T) несомненно ДРУГОЕ представление в памяти, т.е. памяти может потребоваться больше.

DM>>Обычно так, но в некоторых языках бывают и исключения. Например, в Расте Box<T> и Option<Box<T>> представлены в памяти одинаково, потому что первый не может быть нулем, а второй это значение и использует в качестве None.

V>Ну, любой ссылочный тип у нас имеет T+1, потому что мы храним как значение T, так и ссылку на него.


Чего-чего? Не надо про любой ссылочный тип, у них может быть разная семантика.
Трюк как в Option<Box<T>> годится только если Box<T> не может быть нулевым указателем.
Если ты не можешь отличить null как None от null как значение исходного ссылочного типа, то все, приехали, это уже не тот Option из теории типов, это уже кривая поделка, где алгебра не работает и жди проблем.

V>Ну и попутно заметил, что для ссылочных классов многократное "оборачивание" null не требуется.


С т.з. алгебры и теории типов — как раз требуется.
F(T) = T + 1
F(F(T)) = T + 1 + 1 = T + 2
F(F(F(T))) = T + 3
В частности, если T = 1, то F(F(T)) = 1 + 1 + 1 = 3, т.е. тип с тремя разными возможными значениями. Так из Option можно натуральные числа делать.

V>"У дураков мысли сходятся, смотрю" (С)


Верно!
Re[6]: Опциональные типы
От: vdimas Россия  
Дата: 22.02.17 12:14
Оценка: 16 (1) :)
Здравствуйте, D. Mon, Вы писали:

V>>Ну, любой ссылочный тип у нас имеет T+1, потому что мы храним как значение T, так и ссылку на него.

DM>Чего-чего? Не надо про любой ссылочный тип, у них может быть разная семантика.

А если ты имел ввиду, что "ссылочность" значения прячется от системы типов, то ты в этом случае НЕ можешь рассуждать о ссылочном типе — это будет просто некая тонкость реализации.


DM>Трюк как в Option<Box<T>> годится только если Box<T> не может быть нулевым указателем.


Да понятно.
Правда, в этом случае не нужен промежуточный Box<T>, т.е. достаточно лишь Option<T>, не?

Потому что, если я правильно тебя понял насчет устройства Option<> в Rust, то можно был бы сделать так, чтобы из Option<T> получать сразу Box<T> при наличии значения. И такая операция была бы "просто на бумаге", т.е. это было просто приведение типов, а ссылка была бы та же.


DM>Если ты не можешь отличить null как None от null как значение исходного ссылочного типа, то все, приехали


Ссылочный тип по-определению — это зависимый тип.
Тот самый, угу.

Т.е., тип, зависящий от значения:
* валидный адрес — тип T
* нулевой адрес — тип None.


DM>это уже не тот Option из теории типов, это уже кривая поделка, где алгебра не работает и жди проблем.


Тпру-у-у ))

Именно через ссылочный тип реализуют Maybe почти во всех ФП-языках.
Т.е., конечно, можно реализовать Maybe в памяти как явный размеченный union, как структуру с флагом — да как угодно. Но всё это будет тем самым инженерным идиотизмом, когда разработчик не увидел более простого и очевидного решения.

Потому что ссылочный тип уже имеет необходимую семантику зависимого типа. И потому что зависимый тип конечного диапазона можно представить как простой алгебраик (вернее, завернуть зависимый тип в алгебраик, стирая/маскируя "зависимость" типа через сумму типов), что и делается в той же монаде Maybe в Хаскель.

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


V>>Ну и попутно заметил, что для ссылочных классов многократное "оборачивание" null не требуется.

DM>С т.з. алгебры и теории типов — как раз требуется.
DM>F(T) = T + 1
DM>F(F(T)) = T + 1 + 1 = T + 2
DM>F(F(F(T))) = T + 3
DM>В частности, если T = 1, то F(F(T)) = 1 + 1 + 1 = 3, т.е. тип с тремя разными возможными значениями. Так из Option можно натуральные числа делать.

Надеюсь, сейчас ты и сам увидел, что ты малость недопонял, что я тебе говорил?

Смотри, сейчас показал типы, которые в С++ можно было выразить вот так: T*, T**, T*** и т.д.
Да, из этих T***..* можно натуральные числа делать, верное замечание, но это будет детсад, первая четверть и не об этом сейчас речь.

Речь была о том, что в отличие от некоего value-type Nullable<Nullable<...<T>...>>, переменной ссылочного типа можно присвоить просто None (null, NULL, Nil и т.д.) — т.е. присвоить некое значение, НЕ связанное с типом T (а не конструировать значение вот этого страшного типа с длинным именем).

Почему просто null? Потому что это алгебраик — сумма типов.

Дотнет не поддерживает value-type алгебраики, однако, барабанная дробь, тра-та-та-та...
Так почему же C# позволяет писать вот так:
Nullable<int> x = null;

?
Ответ: это хак системы типов сугубо для Nullable<>. Компилятор знает этот тип в лицо (у-у-упс?), т.е. напиши рядом свой аналогичный MyNullable — и будет ошибка компиляции.

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


V>>"У дураков мысли сходятся, смотрю" (С)

DM>Верно!

Ну, мне просто понравилось, что в Rust не стали повторять ошибок дотнета.
Я где-то слышал, что Rust разрабатывали укушенные нейтивом, поэтому "мысли сходятся", ы-ы-ы.
Так-то я этот язык не знаю от слова совсем, спасибо за инфу, как грится.
Re[7]: Опциональные типы
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 22.02.17 12:51
Оценка: +1
Здравствуйте, vdimas,

что-то я перестал понимать твои слова практически.

V>>>Ну, любой ссылочный тип у нас имеет T+1, потому что мы храним как значение T, так и ссылку на него.

DM>>Чего-чего? Не надо про любой ссылочный тип, у них может быть разная семантика.

V>А если ты имел ввиду, что "ссылочность" значения прячется от системы типов, то ты в этом случае НЕ можешь рассуждать о ссылочном типе — это будет просто некая тонкость реализации.


Ничего не понял тут. Еще раз: что именно у тебя здесь означает Т+1 ? Давай не будем вперед паровоза бегать и додумывать друг за друга.


DM>>Трюк как в Option<Box<T>> годится только если Box<T> не может быть нулевым указателем.


V>Да понятно.

V>Правда, в этом случае не нужен промежуточный Box<T>, т.е. достаточно лишь Option<T>, не?

Для чего достаточно? Это разные вещи получатся с разным поведением и разным представлением в памяти.

DM>>Если ты не можешь отличить null как None от null как значение исходного ссылочного типа, то все, приехали


V>Ссылочный тип по-определению — это зависимый тип.

V>Тот самый, угу.
V>Т.е., тип, зависящий от значения:
V>* валидный адрес — тип T
V>* нулевой адрес — тип None.

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

V>Надеюсь, сейчас ты и сам увидел, что ты малость недопонял, что я тебе говорил?


Совсем недопонял, похоже.

V>Речь была о том, что в отличие от некоего value-type Nullable<Nullable<...<T>...>>, переменной ссылочного типа можно присвоить просто None (null, NULL, Nil и т.д.) — т.е. присвоить некое значение, НЕ связанное с типом T (а не конструировать значение вот этого страшного типа с длинным именем).


V>Почему просто null? Потому что это алгебраик — сумма типов.


Ну вот есть ссылочный тип string в условной джаве или шарпе.
Мы можем написать string s = null;
Теперь напиши Option<string> по твоей задумке, да так, чтобы получилось T + 1, а не T.
Отредактировано 22.02.2017 12:53 D. Mon . Предыдущая версия .
Re[7]: Опциональные типы
От: fddima  
Дата: 22.02.17 14:36
Оценка:
Здравствуйте, vdimas, Вы писали:

+1.

V>Т.е., тип, зависящий от значения:

V>* валидный адрес — тип T
V>* нулевой адрес — тип None.

Кстати, хорошая формулировка. Правда на практике нужно переходить к "гарантированно невалидный адрес" — а их практически больше чем просто 0. Так что можно добавить ещё довольно много, если имеет смысл. В принципе представить какой-то { | Error(0..4095) | Success(valid_ptr) } вполне можно. Хотя это больше похоже на какую-то адскую упаковку.

С другой стороны во-всяких широкоизвестных VM подобные трюки активно используются для того что бы представлять часть целых эффективнее.

И да — имхо, только C++ позволяет более-менее это обернуть, сохранив типы (т.е. избавиться от трюкачества) и не растерять перфоманс.

Просто забавно читать как все упёрлись в 0. А как же 1, 2... где же фантазия.
Re[7]: Опциональные типы
От: alex_public  
Дата: 22.02.17 15:15
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Именно через ссылочный тип реализуют Maybe почти во всех ФП-языках.

V>Т.е., конечно, можно реализовать Maybe в памяти как явный размеченный union, как структуру с флагом — да как угодно. Но всё это будет тем самым инженерным идиотизмом, когда разработчик не увидел более простого и очевидного решения.

Ну вообще то ссылочные типы гораздо менее эффективны по определению, из-за введения дополнительной косвенности. Т.е. грубо говоря, если ты сравнишь проход по vector<int*> и vector<optional<int>>, то первый будет в разы медленнее. ) Так что как раз засилье ссылочных типов — это и есть инженерный идиотизм. Но да, если уж это бредовое засилье есть (причём как в Java и C#, безальтернативно — без возможности скажем разместить объект на стеке), то тогда смысла в отдельном классе типа optional действительно уже мало.
Re[8]: Опциональные типы
От: WolfHound  
Дата: 22.02.17 18:04
Оценка: +1
Здравствуйте, alex_public, Вы писали:

_>Ну вообще то ссылочные типы гораздо менее эффективны по определению, из-за введения дополнительной косвенности. Т.е. грубо говоря, если ты сравнишь проход по vector<int*> и vector<optional<int>>, то первый будет в разы медленнее. ) Так что как раз засилье ссылочных типов — это и есть инженерный идиотизм. Но да, если уж это бредовое засилье есть (причём как в Java и C#, безальтернативно — без возможности скажем разместить объект на стеке), то тогда смысла в отдельном классе типа optional действительно уже мало.

1)В .НЕТ есть возможность создавать value типы которые живут в стеке, в массиве или в полях объектов. И там, где они подходят используются именно они. Но часто нужны именно ссылочные типы.
2)Если мы пытаемся получить производительность любой ценой, то массив структур за который ты тут агитируешь тоже инженерный идиотизм.
Вот такой код будет работать медленней и занимать больше памяти
struct Foo
{
  int32 field1;
  int32 field2;
  int32 field3;
  int32 field4;
  int32 field5;
  int32 field6;
  int8  field7;
  int2  field8;
}
Foo array[64*1024];

Чем такой
struct Foo
{
  int32 field1[64*1024];
  int32 field2[64*1024];
  int32 field3[64*1024];
  int32 field4[64*1024];
  int32 field5[64*1024];
  int32 field6[64*1024];
  int8  field7[64*1024];
  int2  field8[64*1024];
}

Посчитай промахи кэша в первом и во втором случае если нам нужно пройтись в цикле по полю field1.
Также посчитает сколько памяти съест выравнивание.

В случае с Option<int32> мы в первом случае получим перерасход памяти и увеличение промахов кэша почти в 2 раза.
А если в массиве много None, то промахов кэша будет ещё больше.

Причем руками можно это всё и не писать.
Можно сделать что-то типа такого:
aos<Foo> array[64*1024];
aos<option<int32>> array[64*1024];

А компилятор сам разобьёт это всё по массивам и уберёт с глаз долой все эти преобразования.
Но С++ так не умеет. Там только руками.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: Опциональные типы
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 22.02.17 18:17
Оценка: :))
DM>F(F(F(T))) = T + 3

А вот так это выглядит:

Re[8]: Опциональные типы
От: WolfHound  
Дата: 22.02.17 18:23
Оценка: +1 -1 :)
Здравствуйте, D. Mon, Вы писали:

DM>что-то я перестал понимать твои слова практически.

Главное то что он сам не понимает о чём он говорит.
В своё время он не смог даже понять формулу альфабленда двух пикселей с альфой и пытался мне доказать, что артефакты на отмасштабированном изображении не от неправильной работы с альфаканалом, а из-за использованного фильтра. Даже не смотря на то что рядом лежало изображение, отмасштабированное тем же фильтром, но с правильной работой с альфаканалом.
Точно такая же история была с многими другими темами.
Например, он долго с умным видом говорил, что знает, как сломать современную криптографию. Когда его наконец загнали в угол и заставили выдать секрет он выдал что-то типа "Злоумышленник может подменить публичный ключ сервера, зашитый в приложение."
После вопроса: "Если злоумышленник может изменить программу, то что ему помешает зашить в эту программу вообще любой вредоносный код?" тихо слился из темы.

Но самое плохо в том, что для людей, которые не понимают о чём идёт разговор он звучит весьма убедительно что приводит к распространению заблуждений.
Короче крайне вредный персонаж.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.