«Специальный формат комментариев» в Javadoc ограничивается добавлением одной звёздочки в начало комментария:
/*
*
*/
vs
/**
*
*/
И всё. Этого достаточно, чтобы такой комментарий подхватился javadoc'ом.
Если вы под «специальным форматом» подразумеваете теги вроде @ code или @ parameter и подобное, то, они, во-первых, для использования абсолютно необязательны, а во-вторых, прошу прощения, в Go их аналогов нет вообще. Это, кстати, лично для меня было очень большим недостатком. В документации ко многим библиотекам на Java или Scala очень часто очень много кросс-ссылок между разными участками документации, в том числе, автоматически сгенерированных (например, в Javadoc можно получить список Known implementors для какого-то интерфейса). В документации Go этого нет, и это очень сильно снижает удобство пользования ей.
Хотелось бы заметить, что продуктивность хоть и связана с языком довольно тесно, но не определяется им (как только языком) на 100%.
Например, существование большого количества разнообразных библиотек и обширное коммьюнити языка, как, например, сейчас есть у Java и C++, серьёзно повышает производительность программистов — если есть библиотеки, то не нужно писать свои, а если есть коммьюнити, то получить ответ на вопрос по языку и библиотекам можно очень быстро. Существование большого коммьюнити, или, другими словами, когда вокруг языка образуется какая-то платформа, очень сильно повышает продуктивность разработчиков, использующих этот язык.
Кроме того, для многих языков получается, что, как только начинаешь с ними работать, продуктивность находится на достаточно низком уровне, но затем, по мере их использования и погружения в сам язык и экосистему, продуктивность очень сильно и быстро возрастает. Лично я отметил это на опыте работы со Scala и Rust, но, я думаю, это верно и для других языков тоже. Например, я долгое время считал, что Scala — это C++ из мира JVM, слишком сложный и перегруженный язык, которым невозможно пользоваться. Такое мнение у меня сложилось, когда я в течение около месяца попытался на нём что-то накодить. Однако, поработав немного на Java и попробовав написать на Scala проект посерьёзнее, моё мнение изменилось на противоположное. Сейчас моим основным рабочим языком является Scala, и я до смерти рад, что мне больше практически не приходится писать на Java. После «вхождения» в язык, изучения его экосистемы и best practices, принятых в коммьюнити, продуктивность работы на языке очень сильно возросла. Как я уже говорил в комментарии к предыдущей статье, у Scala ещё есть множество болячек и неудобных мест, и да, как язык он довольно сложный и «фичастый», но это не меняет того, что код на ней пишется легко и просто, а сложные задачи получается решать весьма продуктивно.
Примерно то же самое я могу сказать про Rust. Я следил за этим языком довольно долго, ещё с того времени, когда он был полностью рантаймовый и со встроенным GC (хотя от встроенных каналов уже успели отказаться), и мне тоже казалось, что он весьма странный и излишне переусложнённый, с его кучей видов указателей. Потом, когда он стал ближе к существующему виду, большую боль вызывала «война» с компилятором и его borrow checker'ом, писать работающий код получалось только с большим трудом. Но после того, как я попытался написать на нём достаточно существенный проект; после того, как поучаствовал в коммьюнити и изучил best practices; после того, как привык к его правилам и начал их применять уже практически неосознанно (и, соответственно, «война» с компилятором прекратилась полностью); после того, как экосистема языка стала достаточно развитой, и появилось множество библиотек и удобные способы работы с ними — после всего этого, что заняло, на самом деле, не так много времени (несколько месяцев привыкания и после этого около полугода до появления нормальной экосистемы и инструментов вроде cargo, а также относительной стабилизации языка), мне писать на Rust очень легко, и я могу решать с его помощью более сложные задачи весьма продуктивно.
Собственно, всё что я хотел сказать — да, язык определяет продуктивность программиста, который на нём пишет, но далеко не на полностью. Огромную роль также играет привычность к правилам языка, знание общепринятых best practices на нём, объём и качество коммьюнити, наличие экосистемы библиотек, наличие инструментов (например, менеджеров зависимостей и IDE). Исключать эти вещи, говоря про продуктивность, по меньшей мере недальновидно.
Да, так и есть, хотя с непривычки (да и не только с непривычки, если честно) программа выглядит страшно :)
К сожалению, Scala, хоть и имеет очень мощную систему типов, не затачивалась на подобные вычисления на этапе компиляции. Например, появляются сторонние костыли попытки улучшения вроде такого. Поэтому выглядит это всё, без преувеличения, ужасно. Тем не менее, причины использовать подобное есть, и довольно весомые.
Программа подсчёта слов на Rust делает гораздо больше чем вышеприведённый пример на D (о чём автор того комментария, кстати, сказал). Я думаю, что аналогичная по функциональности программа на D будет аналогична по длине.
К тому же код в статье можно сделать почище, например, избавиться от лишних as Box<Reader/Writer>.
Мы их используем, наоборот, мы НЕ используем cake pattern как старый компилятор, те — у нас почти все — классы.
Это не противоречит вашему заявлению о том, что классы типов не рекомендуются? И про cake pattern здесь вообще ни слова не было, это совершенно отдельная тема.
Views, кстати, это совсем не то же, что классы типов, по своей семантике.
Его не применяют и планов нет
По крайней мере, про это было сказано в презентации про scala-pickling здесь (страница 55):
Experiment: use Scala-pickling to speed up Scala compiler
Вот это я и говорю, что shapeless это то, что разработчики компилятора и стандартной библиотеки, советуют НЕ использовать
shapeless — может быть, классы типов — сильно сомневаюсь.
Насчёт всего остального — признаю свою ошибку, был не прав.
Я вам скажу вот что, если бы они были хороши, вы бы нашли их в стандатной библиотеке и они бы были использованы в компиляторе. Либо в старом — scalac, либо в новом — dotty.
Они есть в стандартной библиотеке, только мало (например, Numeric или Ordering или ClassTag/TypeTag). Стандартная библиотека связана гарантиями обратной совместимости, и поэтому добавлять туда что-то новое очень трудно. Классы типов в языке возникли сами по себе, на основе имплиситов, и именно поэтому они не используются широко в стандартной библиотеке — когда она создавалась, про них и не думали. Тем не менее, когда их «открыли», соответствующие фичи были добавлены прямо в язык (context bounds же).
В «старом» компиляторе много легаси-кода, который никто не будет переписывать, даже если в этом и есть нужда. Я слабо разбираюсь в компиляторостроении, но далеко не факт, что абстракция классов типов нужна при разработке компилятора, и это может быть объяснением того, что в dotty они не используются.
Также хочу привести в пример scala-pickling, который является официальным проектом Scala, который целиком основан на классах типов и который, насколько я в курсе, хотят применить или уже применяют в компиляторе.
Поэтому единственным аргументом, который вы можете привести в поддержку того, что классы типов это «не то, что вообще рекомендовано к использованию на Scala» — это явные и недвусмысленные заявления членов сообщества, особенно тех, кто обладает достаточным «весом». Без этого такие утверждения — всего лишь ваши собственные рассуждения.
Я этого и не говорил.
…
Например HLists и HMaps намного лучше(и по API и по производительности) реализованы в scala records
Да, возможно я немного преувеличил про «всё», но и вы, мягко говоря, преувеличиваете про HList и HMap. Как я уже сказал, в scala-records ими и близко не пахнет.
это не то, что вообще рекомендовано к использованию на Scala
Весьма странное заявление, особенно про классы типов.
Все что он делает можно реализовать лучше, и сделано уже в сообществе. Например HLists и HMaps намного лучше(и по API и по производительности) реализованы в scala records.
Это заявление очень далеко от реальности. Максимум, на что тянет scala-records — это реализация части функциональности, связанной с record'ами, которые в shapeless представляются в виде HList'а от специального вида пар. Вероятно, для своей области применения scala-records и удобнее, чем shapeless (как частно бывает, что специализированные инструменты удобнее общих), но говорить, что оно полностью заменяет и лучше чем shapeless в целом — это просто троллинг.
Подозреваю, что покормлю тролля, но всё же хочется «принести свет истины». Я хочу возразить по поводу shapeless и вашего превратного восприятия того, зачем эта библиотека нужна, что она делает и как устроена.
В первую очередь, я вынужден признать, что, к сожалению, нормальной документации по shapeless действительно мало. Я не знаю, с чем это связано, но это действительно так, и полного обзора фич shapeless, насколько я знаю, не существует. Здесь вы правы.
Во-вторых, shapeless и тайпклассы связаны примерно так же, как библиотека коллекций (любая, на ваш выбор) и дженерики. shapeless — это всего лишь библиотека, которая основана на тайпклассах. Но сами тайпклассы, как особенность языка, от shapeless совершенно не зависит. Вы свободно можете писать свои классы типов без всяких сторонних библиотек. shapeless нужен для облегчения определённого класса задач, и в своих областях он справляется великолепно. И, соответственно, наоборот — аналог shapeless и его ключевых элементов вроде HList можно реализовать на любом языке, в котором есть необходимые фичи.
Далее,
Чувак убил годы на то, чтобы люди убивали недели и месяцы чтобы сука сослаться на тип, и понять тип значения в рантайме
…
Бебать, да я в 95 программировал на Delpi и у меня все это сразу было. Я ничего не знал про Polymorphic typed λ-calculus, да и сейчас ничего не знаю, но вот цимус в том что и без знаний любой школьник на дельфи, напишет такой HList за 10 минут, и тип в рантайме познает, и сошлется на него, и сравнит и хрен знает что еще.
Вполне очевидно, что вы не поняли, о чём вообще здесь речь и не пожелали разбираться дальше. Хотя бы потому, что «понять тип значения в рантайме» (что, строго говоря, делается с помощью отражения и совершенно не связано с какими-либо библиотеками) — это диаметрально противоположная задача от той, которую выполняет HList. Я очень сильно сомневаюсь, что на дельфи можно написать HList, потому что система типов в дельфи недостаточно мощная для этого, причём в математическом смысле, а не в каком-то абстрактном. Даже если это и можно сделать (как минимум, для этого понадобятся дженерики — версиях дельфи, которые были в 95-м, их вроде бы не было), то сами по себе гетерогенные списки бесполезны — в них важен тот набор операций, который над ними можно осуществлять. А эти операции без продвинутых языковых фич (вроде тех же тайпклассов) описать практически невозможно.
Вы, вероятно, знаете, что такое кортеж (не в смысле Python, а в смысле статически типизированных языков, или, ещё точнее, математики). Это структура данных, содержащая фиксированное количество элементов потенциально различного типа:
val x: (Int, String) = (1, "hello")
println(x._1)
println(x._2)
В типе кортежа указывается, какие типы и в каком порядке могут в нём содержаться, соответственно, (Int, String) != (String, Int).
Гетерогенный список (HList) эквивалентен (изоморфен) кортежу. Абсолютно всё, что возможно сделать с помощью кортежей, можно сделать с помощью HList'ов, и наоборот.
val x: Int :: String :: HNil = 1 :: "hello" :: HNil
println(x.head)
println(x.tail.head)
Однако представление кортежа в виде гетерогенного списка гораздо удобнее при описании операций над ним. Вот здесь приведён список операций, который можно осуществлять над разными гетерогенными структурами, в частности, над HList.
Оставим в стороне вопрос о том, зачем это всё нужно, например, зачем нужны все эти операции. Я могу сказать, что это действительно нужно в определённых областях (например, при создании типобезопасной сериализации или при типобезопасной работе с базами данных), но про это можно рассказывать очень долго. Если вам действительно интересно, то вы можете посмотреть примеры использования shapeless. Я хочу сказать, что вот это:
как ни странно, не предполагается писать пользователям библиотеки. Да, «кишки» shapeless довольно сложны. Однако тем, кто использует её, в большинстве случаев погружаться в них не нужно. Поэтому да, такое вас никто не заставляет «писать каждый день сотнями строк».
Да, Scala — это сложный язык, предоставляющий множество абстракций и имеющий свои «болезни», некоторые из которых довольно неприятные. Но вас никто не заставляет использовать все эти абстракции сразу и целиком. Вот здесь есть хорошее описание «уровней» языковых фич. Если вам не нужно программирование на типах — ок, просто не используйте его и не используйте библиотеки, которые на нём основаны. То же самое с макросами, структурными типами и прочим. Как широко говорилось, вы можете писать на Scala как на Java. Однако некоторые вещи, такие как те же гетерогенные списки (которые, кстати, впервые были сделаны не в Scala, а очень даже в Haskell, если не раньше), сами по себе являются сложными вне зависимости от языка, на котором они сделаны. Поэтому говорить, что язык плохой, потому что на нём, дескать, можно написать сложные библиотеки, по меньшей мере неправильно.
В результате извлекаемые данные требует очень серьезной обработки для расшифровки/восстановления исходной информации и все-равно получаются очень грубыми.
Ну я примерно это и имел в виду) то есть, достать произвольные воспоминания с приемлемой точностью пока что невозможно.
Да, ссылки выше научными исследованиями назвать нельзя. Тем не менее, если существование чего-то не подтверждено достоверными повторяемыми экспериментами, то это весомый повод сомневаться в этом самом существовании.
Но в любом случае, в целом я с вами согласен — до полной разгадки тайн мозга науке только ещё предстоит дойти.
Ну так и в мозге нет такого, чтобы «посмотреть что было раньше». Если смотреть на него «снаружи», например, когда вы спрашиваете человека, что он помнит, это всё равно то же самое распознавание образов: тот, кого вы спрашиваете, получает образ в виде звука и отвечает образом в виде звука. Как вы сами, вероятно, представляете, пока что мы не можем посмотреть в томографе на мозг и достать из него воспоминания. Ну а что происходит «изнутри», когда мы сами что-то вспоминаем для себя — это пока что открытый вопрос, непосредственно связанный с вопросом, чем является сознание. Например, я могу это представить как запрос нейронной сети к самой себе.
Вы что-то не то говорите. Нейронная сеть именно что «помнит». Иначе распознавание образов с её помощью было бы невозможным. Нейронные сети тренируются на предоставленных исходных образцах и затем способны их распознавать.
Мозг — более совершенная и многофакторная нейронная сеть, чем те, что симулируются на компьютере, отсюда и разница в детализации, но суть практически одна и та же — в мозге за счёт переконфигурации связей между нейронами сохраняется информация об образах, полученных из органов чувств.
Возможно, вы имеете в виду то, что нейронные сети на компьютере не могут «осознать» свою память, что бы это ни значило? Ну так в этом ничего удивительного нет. Например, у организмов с простейшей нервной системой есть «память», как выявляется во многих экспериментах, тем не менее, по сложности они недалеко ушли от симулируемых на компьютере. Могут ли они что-нибудь «осознавать»?
Да, сравнение с компьютером не совсем уместно, согласен, однако всё равно имеет смысл делать какие-то оценки информационной плотности.
Если вернуться к науке, пока никто не взял и не показал под микроскопом, что вот в этом нейроне содержится память.
Даже не «память о том-то», а просто память.
Вот это меня удивляет.
Да, так и есть. Однако более-менее однозначно установлена взаимосвязь отдельных частей мозга с конкретными видами памяти. Память в виде самонастраивающейся сети взаимодействующих нейронов — это не просто чисто теоретическая возможность. Даже если взять простейшие нейронные сети, симулируемые на компьютере — вы не сможете сказать, где в каком именно из симулируемых нейронов находится память об образе, на который сеть натренирована. Тем не менее, вполне очевидно, что в целом сеть содержит информацию (если хотите, «помнит») о заданном образе…
Прям таки уж и огромное? Вот например только текст в википедии весит около 25 гигабайт. Я бы не сказал, что текстовой и числовой информации, которая запоминается железно и точно, наберётся хотя бы на сотую часть этого объёма. Это не так уж и много для мозга.
Люди, которые запоминают множество информации, делают это с помощью специальных мнемотехник, основанных на ассоциативной памяти. Это примерно то, про что говорил SpaceEngineer — один и тот же нейрон отвечает за множество «кусков» памяти.
но есть люди с фотографической памятью, а так же люди, способные вновь вспомнить что-то в мельчайших подробностях
люди под гипнозом вспоминают то, что не помнят в обычном состоянии
Ничего особо противоречащего со «сжатием с потерями» здесь нет. При всём желании вы не сможете вспомнить какую-нибудь картинку с такой же точностью, как это может сделать компьютер (до последнего пикселя). Даже если кто-то и помнит мельчайшие детали, всё равно есть некоторый нижний предел разрешающей способности. То, что приходит в ваш зрительный нерв, не записывается, как на камеру — мозг осуществляет очень серьёзный постпроцессинг и выкидывает несущественные детали.
Кроме того, существование фотографической памяти недоказано. Существует феномен эйдетической памяти, но это совершенно другое и вполне укладывается в концепцию «сжатия с потерями», например:
Like other memories, they are often subject to unintended alterations usually because of outside influences
Кроме того, было множество экспериментов, связывающих отдельные типы памяти с различными областями мозга.
Несмотря на то, что сознание и память ещё не «найдены» в полноценном смысле, и их точный механизм не известен до конца, нейробиология, нейрофизиология и прочие связанные науки очень сильно продвинулись в понимании отдельных систем мозга. Утверждение, что память содержится не в мозге, противоречит имеющимся экспериментальным фактам. Почитайте википедию, например.
Способ указывал не я, но в целом я с ним согласен. В конце концов, в памяти хранится далеко не всё, что попадает в органы чувств. Вот например, чем дальше воспоминания в прошлое, тем они расплывчатее. Я бы сказал, что мозг производит «сжатие с потерями», причём довольно эффективное. Для этого нейронов вполне хватит.
Насколько я знаю, мозг разбит на отделы по функциям
Ссылок привести не могу сейчас, но было проведено множество экспериментов, показывающих, как при повреждении мозга функции отдельных частей перераспределяются на ещё неповреждённые участки.
Да от чего будет перестроение таблицы-то? Если регэкспы не меняют исходную строку? (не говоря уже о том, что хеш-таблица здесь — не лучшее решение, массив индексов проще и удобнее будет)
Ну насчёт as_slice() — это вполне естественно. Это вообще по-хорошему должен быть задепрекейченный метод, вместо него Deref и slicing syntax.
Есть ошибки в borrowing механизме
Вот такой код работает:
fn main() {
let v = vec![1, 2, 3, 4];
let mut it = v.iter().peekable();
while let Some(_) = it.peek() {
println!("{:?}", it.next());
}
}
Заметьте, здесь игнорируется результат it.peek(). Если этого не сделать, будет ошибка borrow checker'а, причём совершенно правильная — если бы он разрешил такой код, то после вызова it.next() ссылка, которую бы вернул it.peek(), могла бы стать невалидной, потому что Peekable-итератор буферизует следующий элемент внутри себя, и it.next() его бы уничтожил.
Я не понимаю, как наличие потенциальных, но не обязательных возможностей может порождать стимул не писать комментарии.
И всё. Этого достаточно, чтобы такой комментарий подхватился javadoc'ом.
Если вы под «специальным форматом» подразумеваете теги вроде @ code или @ parameter и подобное, то, они, во-первых, для использования абсолютно необязательны, а во-вторых, прошу прощения, в Go их аналогов нет вообще. Это, кстати, лично для меня было очень большим недостатком. В документации ко многим библиотекам на Java или Scala очень часто очень много кросс-ссылок между разными участками документации, в том числе, автоматически сгенерированных (например, в Javadoc можно получить список Known implementors для какого-то интерфейса). В документации Go этого нет, и это очень сильно снижает удобство пользования ей.
Например, существование большого количества разнообразных библиотек и обширное коммьюнити языка, как, например, сейчас есть у Java и C++, серьёзно повышает производительность программистов — если есть библиотеки, то не нужно писать свои, а если есть коммьюнити, то получить ответ на вопрос по языку и библиотекам можно очень быстро. Существование большого коммьюнити, или, другими словами, когда вокруг языка образуется какая-то платформа, очень сильно повышает продуктивность разработчиков, использующих этот язык.
Кроме того, для многих языков получается, что, как только начинаешь с ними работать, продуктивность находится на достаточно низком уровне, но затем, по мере их использования и погружения в сам язык и экосистему, продуктивность очень сильно и быстро возрастает. Лично я отметил это на опыте работы со Scala и Rust, но, я думаю, это верно и для других языков тоже. Например, я долгое время считал, что Scala — это C++ из мира JVM, слишком сложный и перегруженный язык, которым невозможно пользоваться. Такое мнение у меня сложилось, когда я в течение около месяца попытался на нём что-то накодить. Однако, поработав немного на Java и попробовав написать на Scala проект посерьёзнее, моё мнение изменилось на противоположное. Сейчас моим основным рабочим языком является Scala, и я до смерти рад, что мне больше практически не приходится писать на Java. После «вхождения» в язык, изучения его экосистемы и best practices, принятых в коммьюнити, продуктивность работы на языке очень сильно возросла. Как я уже говорил в комментарии к предыдущей статье, у Scala ещё есть множество болячек и неудобных мест, и да, как язык он довольно сложный и «фичастый», но это не меняет того, что код на ней пишется легко и просто, а сложные задачи получается решать весьма продуктивно.
Примерно то же самое я могу сказать про Rust. Я следил за этим языком довольно долго, ещё с того времени, когда он был полностью рантаймовый и со встроенным GC (хотя от встроенных каналов уже успели отказаться), и мне тоже казалось, что он весьма странный и излишне переусложнённый, с его кучей видов указателей. Потом, когда он стал ближе к существующему виду, большую боль вызывала «война» с компилятором и его borrow checker'ом, писать работающий код получалось только с большим трудом. Но после того, как я попытался написать на нём достаточно существенный проект; после того, как поучаствовал в коммьюнити и изучил best practices; после того, как привык к его правилам и начал их применять уже практически неосознанно (и, соответственно, «война» с компилятором прекратилась полностью); после того, как экосистема языка стала достаточно развитой, и появилось множество библиотек и удобные способы работы с ними — после всего этого, что заняло, на самом деле, не так много времени (несколько месяцев привыкания и после этого около полугода до появления нормальной экосистемы и инструментов вроде cargo, а также относительной стабилизации языка), мне писать на Rust очень легко, и я могу решать с его помощью более сложные задачи весьма продуктивно.
Собственно, всё что я хотел сказать — да, язык определяет продуктивность программиста, который на нём пишет, но далеко не на полностью. Огромную роль также играет привычность к правилам языка, знание общепринятых best practices на нём, объём и качество коммьюнити, наличие экосистемы библиотек, наличие инструментов (например, менеджеров зависимостей и IDE). Исключать эти вещи, говоря про продуктивность, по меньшей мере недальновидно.
К сожалению, Scala, хоть и имеет очень мощную систему типов, не затачивалась на подобные вычисления на этапе компиляции. Например, появляются сторонние
костылипопытки улучшения вроде такого. Поэтому выглядит это всё, без преувеличения, ужасно. Тем не менее, причины использовать подобное есть, и довольно весомые.К тому же код в статье можно сделать почище, например, избавиться от лишних
as Box<Reader/Writer>.Это не противоречит вашему заявлению о том, что классы типов не рекомендуются? И про cake pattern здесь вообще ни слова не было, это совершенно отдельная тема.
Views, кстати, это совсем не то же, что классы типов, по своей семантике.
По крайней мере, про это было сказано в презентации про scala-pickling здесь (страница 55):
shapeless — может быть, классы типов — сильно сомневаюсь.
Насчёт всего остального — признаю свою ошибку, был не прав.
Они есть в стандартной библиотеке, только мало (например, Numeric или Ordering или ClassTag/TypeTag). Стандартная библиотека связана гарантиями обратной совместимости, и поэтому добавлять туда что-то новое очень трудно. Классы типов в языке возникли сами по себе, на основе имплиситов, и именно поэтому они не используются широко в стандартной библиотеке — когда она создавалась, про них и не думали. Тем не менее, когда их «открыли», соответствующие фичи были добавлены прямо в язык (context bounds же).
В «старом» компиляторе много легаси-кода, который никто не будет переписывать, даже если в этом и есть нужда. Я слабо разбираюсь в компиляторостроении, но далеко не факт, что абстракция классов типов нужна при разработке компилятора, и это может быть объяснением того, что в dotty они не используются.
Также хочу привести в пример scala-pickling, который является официальным проектом Scala, который целиком основан на классах типов и который, насколько я в курсе, хотят применить или уже применяют в компиляторе.
Поэтому единственным аргументом, который вы можете привести в поддержку того, что классы типов это «не то, что вообще рекомендовано к использованию на Scala» — это явные и недвусмысленные заявления членов сообщества, особенно тех, кто обладает достаточным «весом». Без этого такие утверждения — всего лишь ваши собственные рассуждения.
Да, возможно я немного преувеличил про «всё», но и вы, мягко говоря, преувеличиваете про HList и HMap. Как я уже сказал, в scala-records ими и близко не пахнет.
Весьма странное заявление, особенно про классы типов.
Это заявление очень далеко от реальности. Максимум, на что тянет scala-records — это реализация части функциональности, связанной с record'ами, которые в shapeless представляются в виде HList'а от специального вида пар. Вероятно, для своей области применения scala-records и удобнее, чем shapeless (как частно бывает, что специализированные инструменты удобнее общих), но говорить, что оно полностью заменяет и лучше чем shapeless в целом — это просто троллинг.
В первую очередь, я вынужден признать, что, к сожалению, нормальной документации по shapeless действительно мало. Я не знаю, с чем это связано, но это действительно так, и полного обзора фич shapeless, насколько я знаю, не существует. Здесь вы правы.
Во-вторых, shapeless и тайпклассы связаны примерно так же, как библиотека коллекций (любая, на ваш выбор) и дженерики. shapeless — это всего лишь библиотека, которая основана на тайпклассах. Но сами тайпклассы, как особенность языка, от shapeless совершенно не зависит. Вы свободно можете писать свои классы типов без всяких сторонних библиотек. shapeless нужен для облегчения определённого класса задач, и в своих областях он справляется великолепно. И, соответственно, наоборот — аналог shapeless и его ключевых элементов вроде HList можно реализовать на любом языке, в котором есть необходимые фичи.
Далее,
Вполне очевидно, что вы не поняли, о чём вообще здесь речь и не пожелали разбираться дальше. Хотя бы потому, что «понять тип значения в рантайме» (что, строго говоря, делается с помощью отражения и совершенно не связано с какими-либо библиотеками) — это диаметрально противоположная задача от той, которую выполняет HList. Я очень сильно сомневаюсь, что на дельфи можно написать HList, потому что система типов в дельфи недостаточно мощная для этого, причём в математическом смысле, а не в каком-то абстрактном. Даже если это и можно сделать (как минимум, для этого понадобятся дженерики — версиях дельфи, которые были в 95-м, их вроде бы не было), то сами по себе гетерогенные списки бесполезны — в них важен тот набор операций, который над ними можно осуществлять. А эти операции без продвинутых языковых фич (вроде тех же тайпклассов) описать практически невозможно.
Вы, вероятно, знаете, что такое кортеж (не в смысле Python, а в смысле статически типизированных языков, или, ещё точнее, математики). Это структура данных, содержащая фиксированное количество элементов потенциально различного типа:
В типе кортежа указывается, какие типы и в каком порядке могут в нём содержаться, соответственно,
(Int, String) != (String, Int).Гетерогенный список (HList) эквивалентен (изоморфен) кортежу. Абсолютно всё, что возможно сделать с помощью кортежей, можно сделать с помощью HList'ов, и наоборот.
Однако представление кортежа в виде гетерогенного списка гораздо удобнее при описании операций над ним. Вот здесь приведён список операций, который можно осуществлять над разными гетерогенными структурами, в частности, над HList.
Оставим в стороне вопрос о том, зачем это всё нужно, например, зачем нужны все эти операции. Я могу сказать, что это действительно нужно в определённых областях (например, при создании типобезопасной сериализации или при типобезопасной работе с базами данных), но про это можно рассказывать очень долго. Если вам действительно интересно, то вы можете посмотреть примеры использования shapeless. Я хочу сказать, что вот это:
как ни странно, не предполагается писать пользователям библиотеки. Да, «кишки» shapeless довольно сложны. Однако тем, кто использует её, в большинстве случаев погружаться в них не нужно. Поэтому да, такое вас никто не заставляет «писать каждый день сотнями строк».
Да, Scala — это сложный язык, предоставляющий множество абстракций и имеющий свои «болезни», некоторые из которых довольно неприятные. Но вас никто не заставляет использовать все эти абстракции сразу и целиком. Вот здесь есть хорошее описание «уровней» языковых фич. Если вам не нужно программирование на типах — ок, просто не используйте его и не используйте библиотеки, которые на нём основаны. То же самое с макросами, структурными типами и прочим. Как широко говорилось, вы можете писать на Scala как на Java. Однако некоторые вещи, такие как те же гетерогенные списки (которые, кстати, впервые были сделаны не в Scala, а очень даже в Haskell, если не раньше), сами по себе являются сложными вне зависимости от языка, на котором они сделаны. Поэтому говорить, что язык плохой, потому что на нём, дескать, можно написать сложные библиотеки, по меньшей мере неправильно.
Ну я примерно это и имел в виду) то есть, достать произвольные воспоминания с приемлемой точностью пока что невозможно.
Но в любом случае, в целом я с вами согласен — до полной разгадки тайн мозга науке только ещё предстоит дойти.
Мозг — более совершенная и многофакторная нейронная сеть, чем те, что симулируются на компьютере, отсюда и разница в детализации, но суть практически одна и та же — в мозге за счёт переконфигурации связей между нейронами сохраняется информация об образах, полученных из органов чувств.
Возможно, вы имеете в виду то, что нейронные сети на компьютере не могут «осознать» свою память, что бы это ни значило? Ну так в этом ничего удивительного нет. Например, у организмов с простейшей нервной системой есть «память», как выявляется во многих экспериментах, тем не менее, по сложности они недалеко ушли от симулируемых на компьютере. Могут ли они что-нибудь «осознавать»?
Да, так и есть. Однако более-менее однозначно установлена взаимосвязь отдельных частей мозга с конкретными видами памяти. Память в виде самонастраивающейся сети взаимодействующих нейронов — это не просто чисто теоретическая возможность. Даже если взять простейшие нейронные сети, симулируемые на компьютере — вы не сможете сказать, где в каком именно из симулируемых нейронов находится память об образе, на который сеть натренирована. Тем не менее, вполне очевидно, что в целом сеть содержит информацию (если хотите, «помнит») о заданном образе…
Прям таки уж и огромное? Вот например только текст в википедии весит около 25 гигабайт. Я бы не сказал, что текстовой и числовой информации, которая запоминается железно и точно, наберётся хотя бы на сотую часть этого объёма. Это не так уж и много для мозга.
Люди, которые запоминают множество информации, делают это с помощью специальных мнемотехник, основанных на ассоциативной памяти. Это примерно то, про что говорил SpaceEngineer — один и тот же нейрон отвечает за множество «кусков» памяти.
Ничего особо противоречащего со «сжатием с потерями» здесь нет. При всём желании вы не сможете вспомнить какую-нибудь картинку с такой же точностью, как это может сделать компьютер (до последнего пикселя). Даже если кто-то и помнит мельчайшие детали, всё равно есть некоторый нижний предел разрешающей способности. То, что приходит в ваш зрительный нерв, не записывается, как на камеру — мозг осуществляет очень серьёзный постпроцессинг и выкидывает несущественные детали.
Кроме того, существование фотографической памяти не доказано. Существует феномен эйдетической памяти, но это совершенно другое и вполне укладывается в концепцию «сжатия с потерями», например:
Кроме того, было множество экспериментов, связывающих отдельные типы памяти с различными областями мозга.
Несмотря на то, что сознание и память ещё не «найдены» в полноценном смысле, и их точный механизм не известен до конца, нейробиология, нейрофизиология и прочие связанные науки очень сильно продвинулись в понимании отдельных систем мозга. Утверждение, что память содержится не в мозге, противоречит имеющимся экспериментальным фактам. Почитайте википедию, например.
Ссылок привести не могу сейчас, но было проведено множество экспериментов, показывающих, как при повреждении мозга функции отдельных частей перераспределяются на ещё неповреждённые участки.
Вот такой код работает:
Заметьте, здесь игнорируется результат it.peek(). Если этого не сделать, будет ошибка borrow checker'а, причём совершенно правильная — если бы он разрешил такой код, то после вызова it.next() ссылка, которую бы вернул it.peek(), могла бы стать невалидной, потому что Peekable-итератор буферизует следующий элемент внутри себя, и it.next() его бы уничтожил.