Вы видите копию треда, сохраненную 9 января 2022 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Medium — http://book.realworldhaskell.org/read
Web — http://www.yesodweb.com/book
Предыдущий тонет здесь: >>1488256 (OP) (OP)
Не прошло и года... А нет, прошло.
Почему? Какие подводные камни?
И этого хватает?
Всё в один эффект пихать? А как же клепание DSL-ек и прочие сексуальные вещи? :o
>реальный хачкель-код за деньги
Ну ты насмешил.
Недавно поковыривал некоторые библиотеки: всё, в чём увлеклись фри монадами, скатилось в нечитаемое перловое говно. Не представляю, как это кто-то поддерживает.
Теглесс нигде не видел.
Как написал анон выше, хочешь сделоть приложение - используй трансформеры.
>> скатилось в нечитаемое перловое говно
Ты точно фри монады ни с чем не путаешь?
>> используй трансформеры
Так это же и есть теглесс.
Не знал, спасибо.
String - последовательность объектов типа Char.
Pattern - пердикат, проверяющий строку на некоторые требования (которые определяют семантику паттерна).
Осталось понять что такое тип
Есть операции сложения и вычитания над этим типом.
Как выразить этот тип в хаскелле? Естсетвенно все ошибки, связанные с несоответствием типа, должны быть в компил-тайме.
>Как выразить этот тип в хаскелле
data MidiNote = One | Two | Three ... TwoHundyredFiftiFive
Ну вопрос был "как выразить этот тип". Типы в хаскелле представляют из себя структуру нихуёв, которые начинают что-то делать с момента бинда к ffi
Можешь использовать Int8 (-127|128) из Data.Int или Word8 из Data.Word
import Data.Word
let myFiveInEightBitBound = 5 :: Word8
При аут оф баунде вроде-как всё пойдёт с нуля, как в сях
Если втупую, то можно используя умные конструкторы.
Например, сделаем такой модуль:
module Satisfy (Pattern(..), Satisfy, satisfy) where
import Data.Proxy(Proxy(..))
class Pattern p a where
tryMatch :: Proxy p -> a -> Bool
data Satisfy a pat where
Satisfy :: Pattern pat a => a -> Satisfy a pat
satisfy :: forall pat a. Pattern pat a => a -> Maybe (Satisfy a pat)
satisfy x
|tryMatch (Proxy @pat) x = Just (Satisfy x)
|otherwise = Nothing
Теперь можем использовать его в других модулях:
data LengthMoreThan5 = LengthMoreThan5
instance Pattern LengthMoreThan5 String where
tryMatch _ s = length s > 5
test1 = satisfy @LengthMoreThan5 "querty" -- Just (Satisfy "querty")
test2 = satisfy @LengthMoreThan5 "qu" -- Nothing
Вместо тысячи слов (которых я и так не знаю, сам не пробовал еще эту магию):
https://habr.com/ru/post/253157/
ВНЕЗАПНО, возможность делать вещи, для которых язык не предназначен.
Вся эта мишура - это уже про зависимые типы. Хочется красоты в этом - надо брать не хаскель, а идрис какой-нибудь.
> Хочется красоты в этом - надо брать не хаскель, а идрис какой-нибудь.
Или пролог с лиспом. В них тоже реализовать зависимые типы в компил-тайме - задача не сложная.
В хаскелле есть система типов, правда слабая. Линейных типов нет, зависимых типов нет. Но система типов хаскелля в любом случае лучше, чем во всяких сях, нимах, джавах.
А вы действительно всерьёз пытаетесь читать Маклейна? Зачем?
Не представляю чем там может заниматься математик
Теория категорий большее отношение имеет к компьютерной лингвистике чем математике
Теория категорий - это не только базовые определения понятий вроде "функтор" и "естественное преобразование".
Во-первых, на Хаскеле за деньги никто не пишет. Вообще, все нормальные люди наоборот донатят на развитие Хаскеля, потому что приколоться за язык хочется, но самому его развивать по понятным причинам лень. Воспринимай Хаскель как сорт оф сообщества стримеров, которые производят интересный контент. Если ты сам хочешь стать стримером.. ну я не знаю.. можно, конечно, но, наверное, надо к этому какую-то предрасположенность иметь.
Теперь, про free и tagless final.
Tagless final в хаскелевкой интерпретации - это что-то вроде абстрагирования по эффекту : f :: (MyConstraint F) a -> F b. Там внутри обычно unwrapped state co-density, которая инлайнится и даёт хорошую производительность. Практически, линейный код на CPS получаешь. Хорошо для всяких парсеров с мелкими функциями, которые будут заинлайнены. Почти стандарт для хаскельлиб.
Free - это интерпретатор. И жесткий DSL. Иногда он красивее, чем tagless final (https://docs.google.com/presentation/d/1VhS8ySgk2w5RoN_l_Ar_axcE4Dzf97zLw1uuzUJQbCo/edit#slide=id.g575348a5eb_0_0). На синтетике медленнее, но в реальной программе всё обстоит сложнее. Все инлайнинги tagless final тоже рано или поздно ломаются, поэтому есть варик забить на них с самого начала и идти по пути free. Ребята, которые бенчмаркают крупные либы (типа Snoyman-а) пишут, что реальной разницы они уже не видят.
Мой совет - вообще не лезть в абстракции, а пиши реальный код с реальными алготитмами. f :: a -> ConcreteEffect b. Когда тебе потребуется навернуть абстракции, тогда уже и навернёшь. Не пытайся разработать сферического коня в вакууме. Пиши как пишется и вводи в свою программу абстракции итеративно по мере необходимости.
>И этого хватает?
Этого не то, что хватает, это будет очень большая проблема, если ты вдруг решишь необоснованно навернуть что-то большее. Вот стартовая точка https://github.com/commercialhaskell/rio
newtype RIO env a = RIO { unRIO :: ReaderT env IO a } - во все поля. Дальнейшее абстрагирование по любому из параметров должно быть обосновано. Иначе ты скатишься в дрочь на абстракции ради абстракций.
>всё, в чём увлеклись фри монадами
Где ты их нашел в библиотеках?
>Теглесс нигде не видел.
Эмм.. ну https://hackage.haskell.org/package/primitive-0.7.1.0/docs/Data-Primitive-MVar.html#v:newMVar. Tagless в мире Хаскеля это как-бы и есть абстракция по эффекту. Но даже это почти нигде не нужно. Большинство реальных библиотек - это a -> ConcreteEffect b.
Если ты пишешь какую-то свою абстрактную библиотеку, которая использует другие конкретные библиотеки и параметризуется эффектами (например, разные эффекты в зависимости от того, в продакшене ты её запустил или в тестовой среде), то там можно либо tagless final (подменяешь словарь функций), либо free (подменяешь интерпретатор).
По сути, это одно и то же. Ну при подмене словаря функций возможен инлайнинг и оптимизации, как я уже писал, но это не точно, что он сработает.
Умеренный point-free - это когда можно скипнуть ненужные аргументы без злоупотребления экзотическими комбинаторами. Думаю, ты и сам понимаешь, в чем разница между liftM4 (,,,) и cata f = c where c = f . fmap c . project и твоё личное отношение к point-free не сильно отличается от отношения к point-free других программистов.
Никак без dependent product. Не усложняй, это не нужно.
>Линейных типов нет
Да как нет, скачай с девелоперской ветки https://gitlab.haskell.org/ghc/ghc/-/wikis/linear-types
Другое дело, что они практически нахуй не нужны. Был бы от них профит, если бы они реально позволяли бы управлять выделением памяти, как в Rust, и делать язык быстрым. Но пока это чисто конструкция на уровне тайпчекера. И раньше можно было подобное делать на параметризованных монадках.
В гугле про них всё правильно расписано. Это раздел сабструктурной логики https://en.wikipedia.org/wiki/Substructural_type_system, где налагаются дополнительные ограничения в ущерб выразительности, но в пользу вычислимости. На практике это означает то, что в некоторой программе можно статичестки отслеживать выделение и освобождение ресурсов. Т.е. написать программу без мусоросборника. Или автоматически гарантировать корректную работу с ресурсами. Но все сабструктурные логики ущербны и не тьюринг-полны.
Однако есть эмпирическое наблюдение, которое заключается в том, что большую часть реальной программы можно записать в какую-нибудь сабструктурную модель и проверить её автоматичести. И только малая её часть потребует тьюринг-полноты, которую можно проверять отдельно вручную. На этом принципе построены такие языки, как Rust или Agda.
В Хаскель тоже добавили линейные типы (вернее добавляют, пока не основной ветке компилятора вроде). Но там они чисто чтобы было. Т.е. если в Rust они используются во полне практических целях, а именно для управления памятью, в Хаскеле они пока использутся (вернее могут быть использованы, когда добавят), чисто для исследований, на скорость работы обычных программ это никак не повлияет.
Вот чем слесарь отличается от инженера. Инженер проектирует, а слесарь выполняет. Инженер должен что-то придумать, а чтобы придумать, надо думать уметь. А слесарь не должен думать, он должен уметь пользоваться инструментом, и ни в коем слечае не думать, а то вдруг придумает что-то другое, а не то, что ему сказали сделать. Слесарь не инженер, он гордится только тем, что умеет пользоваться инструментом.
А теперь посмотрите на толпу хаскелистов и любого энтерпрайзного инженера. Инженер проектирует! У него для этого есть методологии проектирования, парадигмы проектирования, OOD, DDD, даже паттерны у него не чего-попало, а паттерны проектирования, блд! А что хаскелиисты? Зайдите в любой чат и сразу увидите. Хаскель для них все лишь интрумент, они обсуждают сам этот инструмент, никакого проектирования, и им нечем гордиться, кроме своего умения в этот инструмент. Потому что слесари, слесари!
>слесари?
К слову сказать, именно слесарь был тем человеком, который спас меня и квартиру под нами. Слесарь это моя жена.
Так об чем же ж и речь. Чтобы поменять унитаз или откачать засарившуюся канализацию - вы вызываете слесаря. Любой хаскелист тоже подойдет. Потому что проектировать унитаз не надо, это неинженерная работа.
>проектировать унитаз не надо, это неинженерная работа.
Ты уверен? А как же уравнения Навье - Стокса?
Проектируют унитаз в другом месте совсем другие люди. Инженеры. И для проектирования у них есть инженерные методологии и парадигмы проектирования. А Хаскель это инструмент для слесарей, когда надо уже спроектированный другими унитаз поменять. Слава хаскелистам, слава бравым слесарям!
Haskell - это изначально дрочь на инструмент. Просто куча слесарей задумались, а каким должен быть самый лучший инструмент? И выдрочили Haskell.
Не вижу в этом ничего плохого. Люди дрочат на Festool, при этом на стройках работают Бошем и Макитой.
Любой профессиональный работник рано или поздно задумывается не только о продукте, но и о об инструменте. Ведь продукт ты производишь и отдаёшь заказчику. А инструмент - это то, что ты каждый день держишь в своих руках.
Поэтому позиция: "Мне похуй на чем программировать, я же профессионал, а язык - всего лишь инструмент" - это позиция не профессионала, а новичка. Как раз профессионалу не похуй, на чем программировать. И язык для него не "всего лишь инструмент", а "тот самый инструмент, который я каждый день держу в руках, который должен быть самым охуенным и удобным, который должен мотивировать меня к творчеству, который должен быть заточен и изящен, глядя на который, я должен понимать, что и любой продукт, созданный с использованием этого прекрасного инструмента, должен быть таким же качественным и продуманным, как сам инструмент".
Я думаю, так можно и быдлокодеров от программистов отличать. Быдлокодер думает: "Ололо, я выучил Джаву на курсах, как бы чего набыдлокодить побыстрее и заработать денег?" А профессиональный программист разбирается в инструментах и уважает людей, обладающих культурой их использования.
"Вот это японская пила, как ей правильно пилить, чтобы получился красивый срез?" - спрашивает один слесарь. "О, я потратил 10 лет, чтобы овладеть японскими пилами, посмотри видео на моём канале, там я объясняю, под каким углом её приложить и куда надавить, чтобы срез получился максимально аккуратным" - гордится другой слесарь. "РЯЯЯ, МНЕ ПОХУЙ НА ИНСТРУМЕНТЫ, Я ПИЛЮ ЗАГОТОВКИ В ЛЕРУА ПО 20 ШТУК В ДЕНЬ НА СТАНКЕ" - кричит инженегр.
>"РЯЯЯ, МНЕ ПОХУЙ НА ИНСТРУМЕНТЫ, Я ПИЛЮ ЗАГОТОВКИ В ЛЕРУА ПО 20 ШТУК В ДЕНЬ НА СТАНКЕ" - кричит инженегр.
вот замечательно, как подробно описана точка зрения слесаря.
инженер, однако, не "пилит на станке".
он проектирует то, что потом будут пилить слесари (пусть даже 6-го разряда).
проектирует. проектирует. не пилит.
а пока он проектирует, ему не станки нужны, а методология проектирования.
Как будто есть хоть какие-то объективные критерии по которым хаскель лучше джавы
>Просто куча слесарей задумались, а каким должен быть самый лучший инструмент?
Это св. Уодлер то "куча слесарей"?
Нет, вы посмотрите.
Да Уодлер кроме пейперов ничего в жизни не писал, ему слесарить по масти не полагается.
Ошибаешься. Настоящий инженер - это не чирок-пиздунок, рисующий презентации для начальства, а человек, который понимает процесс производства и управляет им.
Я не утверждаю, что инженер может вырасти только из слесаря (или, переводя на компьютерный язык, архитектор не обязательно должен уметь программировать). Это древняя практика, когда мастер вырастал из рабочего. Хотя и рабочая. Ведь такой мастер понимает, как работает его производстно с самых низов. Но это уже не актуально. Сейчас наверняка можно учить архитектора сразу, и не тратить его время на программирование.
Но инженегр, который который вообще нихуя ни в чем не шарит, это как Рогозин в Роскосмосе. Топить такс у тебя получится, даже методологию затопления такс придумаешь, но ты останешься обычным идиотом и ничего компания под твоим управлением не произведёт. Потому что ты тупо не понимаешь принципов работы своих слесарей, значит не можешь ими адекватно управлять.
Хаскель хуже Джавы. Как тебе такое? Хуже/лучше - это функционал, отображающий вектор в упорядоченное кольцо. Дальше порядок и правила отображения можешь сам выбирать. Поэтому со совей "объективнстью" иди нахуй. Может быть для тебя объективность - это искуственный хуй в жопе, с чего ты взял, что всем остальным такие критерии по нраву?
>Хуже/лучше - это функционал, отображающий вектор в упорядоченное кольцо.
Чрезвычайно сомнительное утверждение. Почему в кольцо? Какое ещё кольцо, с какими операциями? Да и вектор из какого пространства?
Априори там только отображение из множества в ЧУМ. Не понимаю, откуда появились дополнительные структуры.
>Но инженегр, который который вообще нихуя ни в чем не шарит
инженер, который не шарит, это уже не инженер, а менеджер! ))
проблема не в том, что инженер не программирует.
проблема в том, что слесарь не проектирует.
т.е. либо кто-то уже напроектировал за него, либо вместо проекта получится Роскосмос.
Бамп вопросу. По основному языку, тайплкасам и основаным на них функторах и монадах тонна статей для тупых, а вот по расширениям, которые много где в хаскеле юзаются, инфу легкую для понимания вебмакакой найти сложно.
Могла бы для начала погуглить значение слова объективность, рвущаяся макака
>Но инженегр, который который вообще нихуя ни в чем не шарит, это как Рогозин в Роскосмосе.
Настоящий инженер проектирует только в UML. Ведь именно для High Kinded Types придумали UML. Да что там, Type Classes, Type Families, - всё это есть только в UML. Отвечай честно и открыто, прямо с ноги: ИН-ЖЕ-НЕ-РИ-Я.
>>1918967
Проще всего посмотреть в гайды ghc и на их гитлабовскую вики. Для совсем макак не уверена, что существуют гайды по этим темам (зачем?), но вот тут http://dev.stephendiehl.com/hask/ довольно много информации по расширениям разбросаны по разным главам.
вы тут сидите и по инерции продолжаете хвалить Х-ль, а тем временем ваш Кметт успел перейти на передовой язык Kotlin:
https://github.com/ekmett/cadenza
Главное чтобы там монадовошь не завелась
Вот и стрелочка повернулась.
Какая именно речь Макарона тебя интересует?
Тогда smart constructor типа
note :: (KnownNat n, n <= 1582) => Proxy n -> Note
note p = Note $ fromIntegral . natVal $ p
И кастомный Num
Но ты ведь не прав, мудила. Язык это действительно всего-лишь инструмент. Все современные языки программирования являются полными по Тюрингу. Какая разница, на каком языке ты будешь вычислять одну и ту же задачу, кроме изъёбистости выполнения оной? На Хаскелле некоторые вещи сделать сложнее, чем на ПХП. Это не делает Хаскелль лучше, это просто complexity bias. Любой алгоритм можно написать на любом ЯПе, ergo любую задачу можно решить на любом ЯПе. Хаскелль это академическая дрочь для изучения возможностей, которые можно привнести в прикладные (прикладные, не Хаскелль, который нихуя не прикладной, что бы ни кукарекали) языки программирования.
Тыскозал?
Из того, что любой алгоритм можно написать не любом ЯП-е не следует, что нет разницы, на каком языке ее писать.
Есть трудозатраты, ограниченность человеческого внимания и т.п..
Пока еще не выросло поколение существ, которые могут писать сложный софт в те же сроки на асме, что и обычные погромисты на подходящих для этого языках.
Идеальный мир, где человек - сверхсущество, которому язык не важен, лишь бы он был Тьюринг-полный - есть только в головах ребят с юношеским максимализмом.
> Из того, что любой алгоритм можно написать не любом ЯП-е не следует, что нет разницы, на каком языке ее писать.
Из того, что любой алгоритм можно написать нa любом ЯП-е не следует, что нет разницы, на каком языке его описывать.
фикс
>прикладные
В этих прикладных языках нормальные абстракции только в scala можно запилить
Почему 99% прикладных языков говно? Почему на свет появляется такое убожество как Go? Это язык полностью мусорный. Сильно развились шарпы и джавы за последние 5 лет? Добавили какого-то говна на пол шишечки, как всегда. Нет никакого привнесения, есть развивающиеся языки и коммерческое гнильцо.
Если на языке нельзя написать монаду то это хуйня а не язык. (За исключением rust, это годный язык)
> Сильно развились шарпы и джавы за последние 5 лет?
Эээ блет на шарп не гони.
В него за последние 5-6 лет как раз и добавили, туплы, паттерн матчинг, рекорды, свитч экспрешоны, кое-какие костыли для работы с наллабл типами.
И вроде как в следущих версиях хотят добавить типы-суммы и тайпклассы.
Да и он первый кто принес в популярные языки async/await, и также благодаря linq многие узнали про всякие map/filter.
> Если на языке нельзя написать монаду то это хуйня а не язык. (За исключением rust, это годный язык)
Алсо, на шарпе можно монаду написать, но не на уровне типов, а в виде "все у чего есть методы Select (fmap) и SelectMany (bind) - монада". Даже аналог ду нотации есть.
>туплы, паттерн матчинг, рекорды, свитч экспрешоны, кое-какие костыли для работы с наллабл типами.
догнали ML 70-го года
>в следущих версиях хотят добавить типы-суммы
а нет, еще не догнали
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b) напиши на шарпе
>благодаря linq
Все так пиарили, а оказалось, что это функции над итератором. Так пропиарили ленивый связный список, ахуеть просто.
Так получилось, что я знаю, что такое эндофунктор и как определяется моноид. Однако я не могу понять, что именно под этими словами понимается в хаскеле, как они толкуются в терминах синтаксиса языка программирования. Статьи с хабра не делают ситуацию понятнее.
Всякий раз разводят какую-то хрень типа функция ретурн имеет этот тип, а байнд - вот этот, а вот сахарок ду.
Монада - наиболее общий тип данных. Любой другой тип данных (список, дерево, к примеру) можно выразить как монаду.
Возможно. Однако где найти точные объяснения, что к чему? Легко понять, что набор данных, в котором объекты - типы, а морфизмы - программы, будет категорией. Но как понятия строятся дальше?
>что именно под этими словами понимается в хаскеле
вот как эта херня запилена в хаскеле
осторожно длинное, и возможно не полезное
class Functor f where
fmap :: (a -> b) -> f a -> f b
вот это тайпкласс для эндофункторов (в хаскеле называется просто Functor)
fmap должен быть такой, что
[Identity] fmap id == id
[Composition] fmap (f . g) == fmap f . fmap g
это законы, без них функтор не функтор
функтор запиливается для типов вида ⋆ -> ⋆
то есть которые берут тип и отдают тип - [], Maybe, тысячи их
для примера инстанс для Maybe
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
fmap применяет f если внутри что-то есть, если нет то нет. простейший функтор
законы работают, как и должны, identity:
>>> fmap id (Just 1)
Just 1
>>> id (Just 1)
Just 1
композиция:
>>> fmap ((+1) . (⋆2)) (Just 1)
Just 3
>>> fmap (+1) . fmap (⋆2) $ (Just 1)
Just 3
между функтором и монадой есть одна шняга, называется апликатив (applicative functor)
это функтор который уже сорт оф моноид, но пока ещё не монада
class Functor f => Applicative f where
pure :: a -> f a
(<⋆>) :: f (a -> b) -> f a -> f b
(в этом классе есть ещё ⋆> и liftA2, о последнем ниже)
каждый апликатив должен быть функтором, иначе он не апликатив
пюре и <⋆> должны быть такие, что
[Identity] pure id <⋆> v = v
[Composition] pure (.) <⋆> u <⋆> v <⋆> w = u <⋆> (v <⋆> w)
[Homomorphism] pure f <⋆> pure x = pure (f x)
[Interchange] u <⋆> pure y = pure ($ y) <⋆> u
я бы сильно в это не вчитывался
но без этих законов апликатив не апликатив
для примера инстанс для Maybe
instance Applicative Maybe where
pure = Just
Just f <⋆> m = fmap f m
Nothing <⋆> _m = Nothing
обратите внимание, что <⋆> выражается через fmap
что нам даёт апликатив:
пюре это возведение a внутрь f (в контекст f)
>>> pure 3 :: Maybe Int
Just 3
<⋆> (название не известно) это вещь в себе
>>> Just (+2) <⋆> Just 1
Just 3
применяется зачастую вот так:
>>> (,,) <$> Just 1 <⋆> Just 2 <⋆> Just 3
Just (1,2,3)
(<$> - это fmap с перевёрнутыми аргументами, в виде инфикс оператора)
немного про liftA2
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<⋆>) (fmap f x)
он выглядит как fmap, и это не случайно: апликатив сорт оф даёт нам композицию эндофункторов
в данном случае - параллельную. в некоторых библиотеках так выражается паралеллизм, например
(,) <$> Future a <⋆> Future b возможно ждёт пока доедут какие-то вычисления или байтики по сети и возвращает нам (a, b)
(это не конкретный пример, а псевдокод)
есть ещё liftA3, liftA4 и выглядят они соответствующе
class Applicative m => Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
в монаде есть ещё >> это частный случай >>=, и return - то же что и pure, но по историческим причинам эта функция есть в обоих тайпклассах.
(>>=) в хаскеле называется bind, в некоторых других языках можно увидеть join или flatMap (не имеет отношения к fmap, ну почти)
законы
[Left identity] return a >>= f = f a
[Right identity] m >>= return = m
[Associativity] m >>= (\x -> f x >>= g) = (m >>= f) >>= g
инстанс для Maybe
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
и примеры законов
Left identity:
>>> return 1 >>= \x -> Just (x+1)
Just 2
>>> (\x -> Just (x+1)) 1
Just 2
Right identity:
>>> Just 1 >>= return
Just 1
ассоциативность не буду приводить, предлагаю поверить на слово
что нам даёт монада - это упорядоченную композицию функторов
допустим у нас есть функция (a -> Maybe b), например она парсит что-то и при успехе возвращает Just b, при неудаче Nothing
мы можем взять и скомпозировать кучу таких функций, но уже упорядочено. в отличии от апликатива, где композиция была другого рода:
a -> Maybe b >>= (b -> Maybe c) >>= (c -> Maybe d) и так далее
вот это - тот самый моноид в категории эндофункторов:
>>= это бинарная операция,
return (или pure) это нулевой элемент,
категория эндофункторов - это множество функций в контексте m (возвращающих значение в контексте m)
такие дела
>что именно под этими словами понимается в хаскеле
вот как эта херня запилена в хаскеле
осторожно длинное, и возможно не полезное
class Functor f where
fmap :: (a -> b) -> f a -> f b
вот это тайпкласс для эндофункторов (в хаскеле называется просто Functor)
fmap должен быть такой, что
[Identity] fmap id == id
[Composition] fmap (f . g) == fmap f . fmap g
это законы, без них функтор не функтор
функтор запиливается для типов вида ⋆ -> ⋆
то есть которые берут тип и отдают тип - [], Maybe, тысячи их
для примера инстанс для Maybe
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
fmap применяет f если внутри что-то есть, если нет то нет. простейший функтор
законы работают, как и должны, identity:
>>> fmap id (Just 1)
Just 1
>>> id (Just 1)
Just 1
композиция:
>>> fmap ((+1) . (⋆2)) (Just 1)
Just 3
>>> fmap (+1) . fmap (⋆2) $ (Just 1)
Just 3
между функтором и монадой есть одна шняга, называется апликатив (applicative functor)
это функтор который уже сорт оф моноид, но пока ещё не монада
class Functor f => Applicative f where
pure :: a -> f a
(<⋆>) :: f (a -> b) -> f a -> f b
(в этом классе есть ещё ⋆> и liftA2, о последнем ниже)
каждый апликатив должен быть функтором, иначе он не апликатив
пюре и <⋆> должны быть такие, что
[Identity] pure id <⋆> v = v
[Composition] pure (.) <⋆> u <⋆> v <⋆> w = u <⋆> (v <⋆> w)
[Homomorphism] pure f <⋆> pure x = pure (f x)
[Interchange] u <⋆> pure y = pure ($ y) <⋆> u
я бы сильно в это не вчитывался
но без этих законов апликатив не апликатив
для примера инстанс для Maybe
instance Applicative Maybe where
pure = Just
Just f <⋆> m = fmap f m
Nothing <⋆> _m = Nothing
обратите внимание, что <⋆> выражается через fmap
что нам даёт апликатив:
пюре это возведение a внутрь f (в контекст f)
>>> pure 3 :: Maybe Int
Just 3
<⋆> (название не известно) это вещь в себе
>>> Just (+2) <⋆> Just 1
Just 3
применяется зачастую вот так:
>>> (,,) <$> Just 1 <⋆> Just 2 <⋆> Just 3
Just (1,2,3)
(<$> - это fmap с перевёрнутыми аргументами, в виде инфикс оператора)
немного про liftA2
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<⋆>) (fmap f x)
он выглядит как fmap, и это не случайно: апликатив сорт оф даёт нам композицию эндофункторов
в данном случае - параллельную. в некоторых библиотеках так выражается паралеллизм, например
(,) <$> Future a <⋆> Future b возможно ждёт пока доедут какие-то вычисления или байтики по сети и возвращает нам (a, b)
(это не конкретный пример, а псевдокод)
есть ещё liftA3, liftA4 и выглядят они соответствующе
class Applicative m => Monad m where
(>>=) :: forall a b. m a -> (a -> m b) -> m b
в монаде есть ещё >> это частный случай >>=, и return - то же что и pure, но по историческим причинам эта функция есть в обоих тайпклассах.
(>>=) в хаскеле называется bind, в некоторых других языках можно увидеть join или flatMap (не имеет отношения к fmap, ну почти)
законы
[Left identity] return a >>= f = f a
[Right identity] m >>= return = m
[Associativity] m >>= (\x -> f x >>= g) = (m >>= f) >>= g
инстанс для Maybe
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
и примеры законов
Left identity:
>>> return 1 >>= \x -> Just (x+1)
Just 2
>>> (\x -> Just (x+1)) 1
Just 2
Right identity:
>>> Just 1 >>= return
Just 1
ассоциативность не буду приводить, предлагаю поверить на слово
что нам даёт монада - это упорядоченную композицию функторов
допустим у нас есть функция (a -> Maybe b), например она парсит что-то и при успехе возвращает Just b, при неудаче Nothing
мы можем взять и скомпозировать кучу таких функций, но уже упорядочено. в отличии от апликатива, где композиция была другого рода:
a -> Maybe b >>= (b -> Maybe c) >>= (c -> Maybe d) и так далее
вот это - тот самый моноид в категории эндофункторов:
>>= это бинарная операция,
return (или pure) это нулевой элемент,
категория эндофункторов - это множество функций в контексте m (возвращающих значение в контексте m)
такие дела
забыл добавить, что все эти тайпклассы можно найти в модуле GHC.Base
документация https://hackage.haskell.org/package/base-4.14.0.0/docs/GHC-Base.html
и сам код https://hackage.haskell.org/package/base-4.14.1.0/docs/src/GHC.Base.html
Борщи, но хорошо расписал.
А ещё говорят что на хаскеле нет реального софта в реальном мире. Собстна, за этим я и зашёл. Какие ещё есть на просторах интернетов легитимные энд-юзер проги на хаскеле? Не пруф оф концепт, а именно реальный софт который используют не вымышленые люди, как XMonad и XMobar.
можешь связаться с компанией MetaLamp (раньше FSD), они пишут на хаскеле, у них еще обучающая программа (роадмап можно сказать) есть по нему
примеры кажецо есть прям на их сайте, но не помню точно
есть какая-то контора, которая регулярно вербует вкатышей, они зачем-то бэк пишут на хаскеле
> что казалось бы только на СИ по хардкору и пердолить реализовано в 500 строчек на высокоуровневом декларативном тайп-сейф языке с производительностью не хуже СИшного аналога dwm.
Та ладно, qtile имеет тот же функционал, но написан на питоне.
> Какие ещё есть на просторах интернетов легитимные энд-юзер проги на хаскеле?
Мало, но они есть. Блокчейн кардано, парсер всего пандок, сервер для постгре postgrest, анализатор баш скриптов shellcheck. Это из тех, которые популярны, опенсорсны и которые юзают не только хаскелисты. Ну а так еще есть termonad, альтернатива гиту и куча софта для разработки на самом хаскеле. сущестует три lsp сервера, каждый дебил создает свой форматировщик и тд
Ну и вот статти по закрытому прод софту на хаскеле: https://serokell.io/blog/top-software-written-in-haskell
> То, что казалось бы только на СИ по хардкору и пердолить
На чем ВМы только не пишут. И на луа есть.
> с производительностью не хуже СИшного аналога dwm
Сам хмонадом пользуюсь, двм, наверное, всё же лучше. Пользовался бы им, если бы конфигурировать было его удобно. В хмонаде просто импортишь и настраиваешь, а в двм патчить надо.
Но и хмонада есть свои проблемы. Хмобар для простенького бара жрёт нормально так оперативки. Если запускаешь игры в полноэкранном режиме, то они нахуй пропадут, если они так запускаются по дефолту, то изволь переходить в другую сессию с другим вм, чтобы в настройках изменить на окно это если нет текстовых файлов настроек нормальных. У меня ещё и табсмод кривовато работает.
Впрочем, пользоваться можно, но не супер, так скажем.
я не говорю что шарпы самый охуенный язык для чистого фп. Но он в этом плане гораздо лучше джавы, плюсов, питонов и тд.
И ты спросил что в него добавили за последние 5 лет. Вроде как дохуя фич.
>>1972858
>>1973275
Ну блять, эта хуета в 2005-2008 появилась. А статейки, где показывали какой хачкиль крутой только потому что в нем есть map и filter, были даже в начале 10х.
>>1972833
Ура, в хаскиле есть аналоги итераторов по будь чему. Очень рад за него.
>Хмобар для простенького бара жрёт нормально так оперативки
Есть dzen2
>Если запускаешь игры в полноэкранном режиме, то они нахуй пропадут
Хуй знает про что ты. Но мой калькулятор тянет только майнкрафт и факторио, и они нормально запускались.
> Хуй знает про что ты. Но мой калькулятор тянет только майнкрафт и факторио, и они нормально запускались.
Не у всех игор такое, но у многих. У меня из последнего что ставил вроде точно не помню встречалось такое с Iratus и Blasphemous.
Идиоматические монады можно писать на чём угодно
>>1978865
>я не говорю что шарпы самый охуенный язык для чистого фп. Но он в этом плане гораздо лучше джавы, плюсов, питонов и тд.
И ты спросил что в него добавили за последние 5 лет. Вроде как дохуя фич.
Каких фич? Даже Фсярп выглядит кастрированно даже на фоне скалы. И нахуй ты это говно сюда тащишь?
>Ура, в хаскиле есть аналоги итераторов по будь чему. Очень рад за него.
Траверс - не итератор
Итератор в рамках хаскеля реализован быть не может, поскольку каждый тайп конструктор в первую очередь является данными с выполнением задач "контейнероности" только на стороне вооброжения программиста
Копроизведения.
Аналог традиционных итераторов из ОО в хаскеле есть и это ленивые связные списки же.
Из разбор - это всё равно что while(iter.next()) { head = iter.getCurrent(); ... }
Так это буквально итератор выходит, всё что можно сделать на итераторах в ОО языке можно сделать используя в качестве итератора ленивые списки.
Не зря же практически у каждой коллекции в хаскеле есть toList, даже у тех, что Foldable не реализуют
Вот это неприятная сторона ФП - мало кто сможет ответить и помочь, нужно много литературы прочесть и много практики. С одной стороны плюс, с другой немножко обидно. Но все же картина понемногу складывается и я понемногу вкатываюсь в алгебраические структуры т.к. уже уверенно чувствую себя в композиции функций и банальном ФП в целом.
Значит, использую Ramda вместе с Redux внедрил на работе, не борщехлеб, пропагандирую ФП среди коллег. Уже задал этот вопрос в рамда тредике англоязычном. В частности, ФП подход удобный из-за того что можно композить селекторы из Редакса (функции с сигнатурой selectorFn :: State -> a ).
Допустим, у нас есть 2 селектора, один из них берет из стейта число, второй массив. И я хочу взять элемент из массива используя этот номер как индекс. В Рамде это может выглядеть так:
>// nthOfList :: [string] -> State -> string
const nthOfList = list => R.pipe(
R.path(["myData", "myIndex"]),
R.nth,
list
);
>// list :: State -> string[]
const list = R.pipe(
R.path(["myOtherData", "myArray"])
);
Теперь чтобы взять элемент по индексу я передаю стейт в эти функции и применяю результат list к nthOfList
// >f(g(x), x)
const elementByIndex = nthOfList(list(state))(state);
Очевидно, это становится тяжело читать. И я узнаю что здесь можно применить chain:
const elementByIndex = R.chain(nthOfList, list);
elementByIndex(state);
Теперь, вопрос: это ведь какой-то паттерн в ФП, правда? Могли бы ли вы анончики подсказать что это значит, что эти два селектора можно выразить через chain, ведь сhain это одна из функций Monad тайп класса, так ведь? Вопрос скорее более абстрактный, чем конкретный - возможно вы еще сможете направить меня на какую-то книжку или подсказать что Редакс это на самом деле Update монада. Я чувствую что с этими селекторами есть некоторое объединяющее их свойство - а именно State как финальный первый параметр всегда - и что я могу упростить композицию селекторов завернув их во что-то, что всегда будет вызывать их передавая в них стейт как только я скажу "run" финальному селектору. Если это имеет смысл то что я сказал.
Вот это неприятная сторона ФП - мало кто сможет ответить и помочь, нужно много литературы прочесть и много практики. С одной стороны плюс, с другой немножко обидно. Но все же картина понемногу складывается и я понемногу вкатываюсь в алгебраические структуры т.к. уже уверенно чувствую себя в композиции функций и банальном ФП в целом.
Значит, использую Ramda вместе с Redux внедрил на работе, не борщехлеб, пропагандирую ФП среди коллег. Уже задал этот вопрос в рамда тредике англоязычном. В частности, ФП подход удобный из-за того что можно композить селекторы из Редакса (функции с сигнатурой selectorFn :: State -> a ).
Допустим, у нас есть 2 селектора, один из них берет из стейта число, второй массив. И я хочу взять элемент из массива используя этот номер как индекс. В Рамде это может выглядеть так:
>// nthOfList :: [string] -> State -> string
const nthOfList = list => R.pipe(
R.path(["myData", "myIndex"]),
R.nth,
list
);
>// list :: State -> string[]
const list = R.pipe(
R.path(["myOtherData", "myArray"])
);
Теперь чтобы взять элемент по индексу я передаю стейт в эти функции и применяю результат list к nthOfList
// >f(g(x), x)
const elementByIndex = nthOfList(list(state))(state);
Очевидно, это становится тяжело читать. И я узнаю что здесь можно применить chain:
const elementByIndex = R.chain(nthOfList, list);
elementByIndex(state);
Теперь, вопрос: это ведь какой-то паттерн в ФП, правда? Могли бы ли вы анончики подсказать что это значит, что эти два селектора можно выразить через chain, ведь сhain это одна из функций Monad тайп класса, так ведь? Вопрос скорее более абстрактный, чем конкретный - возможно вы еще сможете направить меня на какую-то книжку или подсказать что Редакс это на самом деле Update монада. Я чувствую что с этими селекторами есть некоторое объединяющее их свойство - а именно State как финальный первый параметр всегда - и что я могу упростить композицию селекторов завернув их во что-то, что всегда будет вызывать их передавая в них стейт как только я скажу "run" финальному селектору. Если это имеет смысл то что я сказал.
Это значит что функции с фиксированным типом входного аргумента является монадой и соответственно такие функции можно комбинировать через функцию (>>=)
До сих пор не понимаю, зачем ты пытаешься на хаскель натянуть именно слово "итератор"
>Не зря же практически у каждой коллекции в хаскеле есть toList, даже у тех, что Foldable не реализуют
Каждая коллекция и является траверсабельной, а не итерабельной
Далеко не все коллекции реализуют что Foldable, что Traversable. Простейщий пример - IntSet и ему подобные.
Тут дело в том, что между ОО итератором и хаскелевским списком можно буквально изоморфизм построить.
Т.е. вот пример, тут мы в качестве ОО итератора возьмем тайпкласс имеющий условно интерфейс как у ОО итератора + экзистенциальный тип и получим Iter a, который полный аналог интерфейса итератора из любого ОО языка.
Ну и сам изоморфизм и всё такое:
class Iterator this a where
next :: this -> Maybe (a, this)
data Iter a = forall this. (Iterator this a) => Iter this
instance Iterator [a] a where
next [] = Nothing
next (x:xs) = Just (x, xs)
iteratorIso :: Iso' (Iter a) [a]
iteratorIso = iso toList fromList where
fromList :: [a] -> Iter a
fromList = Iter
toList :: Iter a -> [a]
toList (Iter initial) = unfoldr next initial
И условный пример подобных итераторов, чтобы можно было убедиться, что изоморфизм действительно работает ожидаемым образом:
data RangeState = RangeState { start :: Int, until :: Int }
instance Iterator RangeState Int where
next RangeState { start, until } | start == until = Nothing
| otherwise = Just (start, RangeState { start = start + 1, until })
newtype InfiniteState = InfiniteState { start :: Int }
instance Iterator InfiniteState Int where
next InfiniteState { start } = Just (start, InfiniteState { start = start + 1 })
Тут дело в том, что между ОО итератором и хаскелевским списком можно буквально изоморфизм построить.
Т.е. вот пример, тут мы в качестве ОО итератора возьмем тайпкласс имеющий условно интерфейс как у ОО итератора + экзистенциальный тип и получим Iter a, который полный аналог интерфейса итератора из любого ОО языка.
Ну и сам изоморфизм и всё такое:
class Iterator this a where
next :: this -> Maybe (a, this)
data Iter a = forall this. (Iterator this a) => Iter this
instance Iterator [a] a where
next [] = Nothing
next (x:xs) = Just (x, xs)
iteratorIso :: Iso' (Iter a) [a]
iteratorIso = iso toList fromList where
fromList :: [a] -> Iter a
fromList = Iter
toList :: Iter a -> [a]
toList (Iter initial) = unfoldr next initial
И условный пример подобных итераторов, чтобы можно было убедиться, что изоморфизм действительно работает ожидаемым образом:
data RangeState = RangeState { start :: Int, until :: Int }
instance Iterator RangeState Int where
next RangeState { start, until } | start == until = Nothing
| otherwise = Just (start, RangeState { start = start + 1, until })
newtype InfiniteState = InfiniteState { start :: Int }
instance Iterator InfiniteState Int where
next InfiniteState { start } = Just (start, InfiniteState { start = start + 1 })
Линзы хороши, но там у меня функции не только проперти читают.
В рамда чятике ответили - у меня случай Reader монадки. Алсо, палю годноту: https://gist.github.com/Avaq/1f0636ec5c8d6aed2e45
Cажа приклеилась
>между ОО итератором и хаскелевским списком
Между нехаскелевским нельзя?
>условно интерфейс
>экзистенциальный тип
И получаем "условный "интерфейс" итератора, который в рамках самого хаскеля - траверс обычной структуры
Итератор подразумевает "контейнеринг" каких-то "данных", на абстрактном уровне чистого ФП с иммутабельными копиями это не имеет никакого смысла
А линзы и не только для чтения пропертей.
Ну подобный итератор с экзистенциалом делает ровно то же, что и его ОО собрат, пряча точный тип обходимого контейнера внутри себя.
>не только проперти читают
Ты просто с ними не знаком
https://www.codewars.com/kata/54258ffb430ca2e4b5000239/train/haskell
>Между нехаскелевским нельзя?
Тут нужен именно иммутабельный ленивый список, это важная деталь.
А так-то в других языках тоже можно подобный трюк провернуть, если есть желание:
https://scastie.scala-lang.org/D5U6II7hQxOySByOo4352A
Спасибо
> Несколько месяцев заходил в этот тред и видел, что новых сообщений нет
> "хаскель тред совсем мёртвый стал"
> всё это время существовал другой тред
>маам мой хацкиль всем очинь нужён
А что ты скажешь о том простом факте что твой фп-код под капотом превращается в код на императивном C да и рекурсия твоя оптимизируется в цикл?
Это машины так тебя заставляют думать.
господа, што такое фри монады и таглес файнал? есть годные источники по изучению этой нечести?
я наверно в шары долбился, но не видел этих тем. пойду гляну еще раз.
Файнал монады похожи на привычную из ООП историю об интерфейсе и имплементации:
- создаёшь тайпкласс, который описывает какой-то интерфейс
- создаёшь свою кастомную монаду
- привязываешь их друг к другу, объявив инстанс тайпкласса для монады, т.е. объявляешь свою кастомную монаду имплементацией интерфейса-тайпкласса
- разные функции ожидают интерфейс, а ты им подкидываешь имплементацию.
Фри монады тот же интерфейс объявляют не в виде тайпкласса, а в виде GADT. А имплементация интерфейса превращается в интерпретацию операций - объявляешь какую-то функцию-интерпретатор из фри монады в кастомную монаду. Ты как будто внутри языка создаёшь ещё один интерпретируемый язык и интерпретатор для него.
Ты потерял важную деталь - таглесс файнал позволяет далеко не только монады описывать, а фри монады - это именно про интерпретирование монады с кастомными действиями в целевую монаду
Спасибо. Очень интересно, буду разбираться дальше.
Ещё нужно добавить, что в файнал подходе функции перечисляют как минимум два тайпкласса: один, который ты создал как интерфейс создаваемой тобой монады, а второй - это собственно тайпкласс Monad.
Хотя наверное иногда можно обойтись без объявления об ожидании тайпкласса Monad.
Конечно, можно, и более того, лучше не указывать Monad, если можно обойтись более слабыми конструкциями, типа функтуров, аппликативов, селективов и стрелок.
По сути в final tagless подходе, ты с помощью своего тайпкласса указываешь необходимые в данной доменной области операции, а с помощью второго тайпкласса типа Monad, Applicative и т.п. указываешь, как эти операции можно скомбинировать в программу.
И сила как раз final tagless, в том, что эти две вещи: доменные операции и способ их комбинирования - полностью независимы друг от друга.
Но и о недостатках нужно помнить.
Александр Гранин хорошо в своих докладах описывал недостатки FT.
Среди них как раз всплывание всего списка низкоуровневых эффектов (деталей реализации) в констрейнтах домена и сложности разграничения эффектов в разных слоях логики.
https://youtu.be/u1GGqDQyGfc
Ох, не надо слушать Гранина неиронично, он сам TF плохо понимает.
Если у тебя в TF каким-то образом в эффектах вверх всплывает MonadUnliftIO (или Sync в случае скаловских котов) - значит ты свою доменную модель спроектировал неправильно.
Потому что в доменном коде при TF у тебя не должно быть подобных эффектов, они слишком мощные для доменного кода.
Ну и фри монады, опять-таки норм использовать как Гранин их подразумевает, только в крупных фреймворках и около всякого IO, где их нулевая производительность и дикий GC pressure никому не помешают.
А TF в грамотно написанном по перформансу коде (а это в случае хаскеля значит - инлайним и специализируем ВСЁ что видим) - имеет практически нулевую цену.
Это всё, конечно, хорошо, но где же можно воочию лицезреть тот самый "правильный" TF, в таком случае?
Ну и сам факт того, что на TF так легко писать "неправильно", уже о чем-то говорит, ведь в больших проектах если где-то можно писать неправильно, то оно БУДЕТ написано неправильно.
(Но видео-то глянь, там не только UnliftIO всплыло)
Я на этом докладе лично был и реакция аудитории там всё говорила.
На TF сложно писать неправильно как раз по той причине, что любую такую утечку неограниченных эффектов будет явно видно в сигнатуре.
А с вариантом с фри монадами, у тебя будет какой-нибудь runAnyEffect :: IO a -> MyFreeMonad a и всё, ты никогда не узнаешь, что он где-то там внутри используется.
> runAnyEffect
Но такую штуку же будет сразу видно. Так себе в ногу и в FT можно выстрелить.
И всё же, есть какие-нибудь исходники, которые можно почитать на пример расово верного TF?
В статейках всё красиво обычно, но это либо очень просто, либо вырвано из контекста. Хотелось бы посмотреть на TF "в естественной среде обитания", так сказать.
> Но такую штуку же будет сразу видно.
Такую штуку будет видно, только если напрямую лезть в исходники и смотреть, а что же там написано и какие эффекты фри монады юзаются.
А вот использование всяких UnliftIO видно сразу в сигнатуре функций их использующих.
Я имею в виду, что присутствие такой вот в сорцах вообще
> runAnyEffect
должно приводить к хорошему подзатыльнику автора сей поделки.
И очевидно, что сделать такой вот runAnyEffect можно в общем лишь имея в скоупе конструкторы дата структуры, на которой построена фри монада. Так что если это не говнокод, где фри монада заимплементирована в том же модуле, где лежит ее интерпретатор и код, ее использующий, или где всё экспортируется везде, то такого рода сомнительные функции будут хорошо заметны, находясь в модуле с определением фри монады, или с ее интерпретатором.
Короче, если не мудачить прям совсем безбожно (нарушая все возможные принципы проектирования ПО), то сложно представить, как можно такую проблему получить.
Ну вот у Гранина как раз во фри монадах его фреймворков вроде обычно есть такие конструкторы фри монады, чтобы сторонние библиотеки можно было легко подключить к текущему эффекту.
И проблема как раз в том, что ты не посмотрев исходники данной функции - не поймешь, используется ли она такие черные ходы в IO или нет.
Как и любая другая монада
Интерфейс для случаев выхода в реал ворлд находится на уровне интерпритации компелятором
Т.е не весь язык можно описать в терминах самого языка? Какой-то ограниченный язык.
А как тогда делать кастомную монаду с эффектами?
Ты не понимаешь ни что такое монада, ни что такое эффект, но хочешь монаду с эффектом. лол
Ок переформулируем.
Как компилятор понимает какую монаду интерпретировать, а какую не интерпретировать?
Вот из его фреймворка пример:
https://github.com/graninas/Hydra/blob/master/lib/hydra-free/src/Hydra/Core/Lang/Language.hs#L35
Короче, краткий курс по монадам и IO в хаскеле.
Есть у нас красивый ленивый язык (где аргументы переданные в функцию вычисляются только при их использовании).
Как сделать в нём ввод и вывод так, чтобы пользователю языка не оторвало руки от ленивости и компилятор знал какие обращения к вводу и выводу должны когда идти и когда их порядок нельзя менять?
Ответ простой - надо чтобы все подобные эффекты принимали и возвращали какой-то токен, который компилятор не может создать из ничего и таким образом установить для компилятора жесткий порядок между побочными эффектами.
Собственно тогда каждая функция с побочным эффектом будет выглядить как Token -> (ReturnType, Token), но руками такие функции соединять друг с другом не очень удобно, т.к. будет бойлерплейт в духе:
(value, token1) = myEffect1 token0
(value2, token2) = myEffect2 token1
(value3, token3) = myEffect3 token2
Но можно написать такую функцию, которая будет этот токен за нас пробрасывать:
type MyIO a = Token -> (a, Token)
bind :: MyIO a -> (a -> MyIO b) -> MyIO b
И вот мы и приходим к тому, что наше IO будет монадой (т.к. map, pure, <$> для него легко по аналогии написать).
И если залезть в base хаскеля то там именно оно и будет и любое IO можно разобрать в подобную функцию с State# RealWorld -> (# State# RealWorld, a #):
https://hackage.haskell.org/package/base-4.15.0.0/docs/src/GHC-Base.html#unIO
>>2003537
> И проблема как раз в том, что ты не посмотрев исходники данной функции - не поймешь, используется ли она такие черные ходы в IO или нет.
Можно задокументировать это, создав инстанс MonadIO.
>>2002186
Что-то не понял пример про runAnyEffect :: IO a -> MyFreeMonad a.
Делать свою монаду инстансом MonadIO - это плохо?
> Т.е не весь язык можно описать в терминах самого языка? Какой-то ограниченный язык.
То же самое можно сказать о математике и логике.
А вообще вопрос интересный, можно ли создать монаду более фундаментальную и низкоуровневую что IO.
*чем IO
Можно задокументировать это, создав инстанс MonadIO, но так тогда тебе всё равно придется писать в final tagless стиле, чтобы MonadIO в констрейнтах функций было видно, где эти черные ходы юзаются.
> Делать свою монаду инстансом MonadIO - это плохо?
Ты делаешь свой доменный эффект для бизнес логики, а потом в центре него оставляешь дыру через которую можно любой произвольный эффект сделать?
Спрашивается - почему бы сразу и не писать в конкретном эффекте, если ты всё равно оставяешь такую штуку?
> То же самое можно сказать о математике и логике.
Имеется в виду, что в языке есть те функции, которые определить невозможно. В C к примеру все функции определены, так как сишка это ассемблер на спидах. В JS тоже множество функций, у которых просто НЕТ определения. Операция плюс, или console.log, к примеру. И это бесит.
В си дофига зато аттрибутов и макросов, которые невозможно выразить в языке, потому что они управляют именно поведением компилятора.
И опять-таки примитивные типы, которые ты никак на самом языке не опишешь и т.п.
>(value, token1) = myEffect1 token0
(>value2, token2) = myEffect2 token1
>(value3, token3) = myEffect3 token2
Вот это вот очень сильно похоже на аффинные типы в клин/меркари, только там токен обозначает измененный мир.
main(IO0, IO) :-
io.write_string("fib(10) = ", IO0, IO1),
io.write_int(fib(10), IO1, IO2),
io.nl(IO2, IO).
https://en.wikipedia.org/wiki/Mercury_(programming_language)#Examples
Mode declarations can also specify so-called “unique modes”. Mercury’s unique modes are similar to “linear types” in some functional programming languages such as Clean. They allow you to specify when there is only one reference to a particular value, and when there will be no more references to that value. If the compiler knows there will be no more references to a value, it can perform “compile-time garbage collection” by automatically inserting code to deallocate the storage associated with that value. Even more importantly, the compiler can also simply reuse the storage immediately, for example by destructively updating one element of an array rather than making a new copy of the entire array in order to change one element. Unique modes are also the mechanism Mercury uses to provide declarative I/O.
https://www.mercurylang.org/information/doc-latest/mercury_ref/Unique-modes.html
Но очевидно что монады и аффинные типы это разный подход, даже концептуально, так что что-то тут не чисто.
На каком-то этапе ты переходишь от Си к Ассемблеру.
Опиши цикл for в терминах самого цикла for, не переходя в Ассемблер? Си какой-то ограниченный.
А если можно переходить из одного языка в другой, то точно так же переходим от Хаскеля на тот язык, на котором написан компилятор Хаскеля.
Ну тут деталь, что ядро языка в хаскеле очень маленькое (считай тупо лямбда исчисление) и чтобы его не усложнять, всякие магические вещи, которые в других языках являются его конструкциями (например та же работа с указателями) в хаскеле сделана через такие магические функции, которые при кодгене компилятор уже раскрывает в нужные операции.
Я могу описать функцию print условно как:
print x -> какой-то байткод
Т.е смог определить функцию. У хаскелла же какая-то черная магия, которая "просто работает".
Это по сути тот же приём, только без явного использования афинных типов и со спрятыванием пробрасывания токена под капот IO.
Ну и с возможностью слома всей этой системы, если особо нужно, т.к. токен не афинный и не линейный и если ты хочешь найти себе приключений на свою задницу, то ты можешь его явным копированием сделать кучу хитрых трюков.
И заодно сделать эффективное ленивое IO при этом, т.к. некоторые ленивые операции с вводом выводом в хаскеле сделаны именно так через дублирование токена: см http://hackage.haskell.org/package/base-4.14.1.0/docs/src/GHC.IO.Unsafe.html#unsafeDupableInterleaveIO и ему подобные функции, через которые ленивыйввод вывод можно выразить.
Ну если байткод считать валидной конструкцией языка, то как бы да, полноценный язык. Но понятно же, что это не язык полноценный, а смесь двух языков, просто язык позволяет встраивать в свои исходники инструкции на другом языке (если я правильно понял пример с print).
Теоретически можно было бы все языки сделать полноценными, позволив встраивать в их исходники байткод. Но ты же не будешь серьёзно этого требовать.>>2003630
Ну в хаскеле по сути несколько внутренних представлений сравнимых с байткодом и при особом желании их все можно компилятору скормить при желании.
Т.е. есть Core, STG и CMM и на них вполне себе можно попробовать отдельно написать код и слинковаться, вроде бы кто-то так даже делал. И где-то весит пропозал на то, чтобы функции в этих представлениях можно было явно инлайнить в исходники.
А как в erlang сделали так, чтобы можно было на ходу заменять части программы? Почему именно erlang? Может и в хаскеле такое появится?
Ты уже давно протёк
Потому что у эрланга байткод именно выполняется в рантайме, а в хаскеле - все эти представления существуют только на этапе компиляции, т.к. хаскель в итоге в машинный код компилится.
> Ты делаешь свой доменный эффект для бизнес логики, а потом в центре него оставляешь дыру через которую можно любой произвольный эффект сделать?
> Спрашивается - почему бы сразу и не писать в конкретном эффекте, если ты всё равно оставяешь такую штуку?
Потому что в доменном эффекте удобнее описать действия?
Ну, типа, как делают в ORM-ах, которые object relational mapping. Там обычно есть какое-то API или DSL для создания запросов, и где-то с краю есть возможность запустить запрос, описанный в виде обычного SQL в строке.
Ну хорошо, если поставить перед собой цель убрать эту дыру, то как это делается?
Вот тебе нужно, чтобы вместе с твоими доменными операциями можно было выполнять IO-операции.
Такой пример: есть какая-то монада с состоянием (State или StateT), которую я объявил как MonadIO.
Пользователь может вызвать любое IO-действие вместе с действиями моей монады, но эти действия не меняют состояние, хранящееся в монаде. Что в этом плохого?
Меня больше интересует вопрос, как в одном блоке работать с двумя разными состояниями. Объединять две монады в один стек монад? Какой есть способ, минимизирующий церемонии и свистопляски с типами?
Потому что в эрланг это всего лишь
loop(Func, State) ->
__receive
____{apply, Data, Pid} ->
______{Result, NewState} = Func(Data, State)
______Pid ! Result
______loop(Func, NewState)
____{code_change, NewFunc} ->
______loop(NewFunc, State)
__end.
Ну и там сразу рантайм на это заточен, загрузка нового кода, хранение старой и новой версии кода, переключение. Но даже там для stateful частей чаще всего очкуют его юзать, так как нужно много чего предусмотреть, нужно или новый код писать с расчетом на то, чтоб он не распидорасил старый стейт, либо, что еще сложнее, мигрировать стейт, что подразумевает фриз старого кода на время миграции, что уже не совсем риал-тайм, ну то есть оно все еще неплохо что можно зафризить отдельные части и действовать по-этапно, но это пиздец какие тонкие инженерные изьебы и на большинстве задач людям просто проще переключить один контейнер на другой в кубере.
Наверное есть какие-то паттерны специально для таких случаев.
Что-то вроде CRDT, который будет постепенно переезжать из старой версии в новую, а когда переезд закончен, старая версия благополучно отклучается и остаётся только новая.
Если мы говорим про final tagless, то если мы хотим, чтобы у нас констрейнты на функции говорили нам о том, какие эффекты мы можем применить:
confirmOrders :: (HasAccountDb m, HasBookKeepingService m, HasAccountCache m, MonadPlus m) => [Order] -> m [ConfirmedOrder]
И таким образом мы знаем, что в этой функции никаких черных ходов не используется и всё что она может сделать - это вызвать одну из функций из выше перечисленных тайпклассов.
И если на этой функции будет констрейнт MonadIO, то мы теряем вот эту возможность знать, что внутри за хрень будет происходить. Потому что это значит, что там внутри будет всё что угодно.
> Объединять две монады в один стек монад? Какой есть способ, минимизирующий церемонии и свистопляски с типами?
У тебя есть MonadState, с его помощью можно сделать такой трюк:
newtype State1 = State1 { testOne :: Int }
newtype State2 = State2 { testTwo :: Int }
workingWithTwoStates :: (MonadState State1 m, MonadState State2 m) => m ()
workingWithTwoStates = do
__x <- gets testOne
__y <- gets testTwo
__let updateFirst state = state { testOne = x + y }
____updateSecond state = state { testTwo = x + y }
__modify updateFirst
__modify updateSecond
А дальше можно для твоей монады в приложении newtype MyApp a = MyApp { runMyApp :: StateT CombinedState ... } через кунг фу на deriving via и HasField автоматически вывести MonadState State1 и MonadState State2, которые являются полями в CombinedState
Если мы говорим про final tagless, то если мы хотим, чтобы у нас констрейнты на функции говорили нам о том, какие эффекты мы можем применить:
confirmOrders :: (HasAccountDb m, HasBookKeepingService m, HasAccountCache m, MonadPlus m) => [Order] -> m [ConfirmedOrder]
И таким образом мы знаем, что в этой функции никаких черных ходов не используется и всё что она может сделать - это вызвать одну из функций из выше перечисленных тайпклассов.
И если на этой функции будет констрейнт MonadIO, то мы теряем вот эту возможность знать, что внутри за хрень будет происходить. Потому что это значит, что там внутри будет всё что угодно.
> Объединять две монады в один стек монад? Какой есть способ, минимизирующий церемонии и свистопляски с типами?
У тебя есть MonadState, с его помощью можно сделать такой трюк:
newtype State1 = State1 { testOne :: Int }
newtype State2 = State2 { testTwo :: Int }
workingWithTwoStates :: (MonadState State1 m, MonadState State2 m) => m ()
workingWithTwoStates = do
__x <- gets testOne
__y <- gets testTwo
__let updateFirst state = state { testOne = x + y }
____updateSecond state = state { testTwo = x + y }
__modify updateFirst
__modify updateSecond
А дальше можно для твоей монады в приложении newtype MyApp a = MyApp { runMyApp :: StateT CombinedState ... } через кунг фу на deriving via и HasField автоматически вывести MonadState State1 и MonadState State2, которые являются полями в CombinedState
Либо сделать самый простой способ и держать всё состояния в рамках одного CombinedState и везде бегать с MonadState CombinedState m
Это тоже вариант, при этом вполне себе удобный, в особенности если запастить линзами.
> И таким образом мы знаем, что в этой функции никаких черных ходов не используется и всё что она может сделать - это вызвать одну из функций из выше перечисленных тайпклассов.
> И если на этой функции будет констрейнт MonadIO, то мы теряем вот эту возможность знать, что внутри за хрень будет происходить. Потому что это значит, что там внутри будет всё что угодно.
Я понимаю, если бы ты своё состояние держал в IORef-ах - тогда да, ты не знаешь, что там творится в этих IO-действиях: они рисуют на экране или портят состояние твоего приложения. Но если ты не используешь IORef-ы и другие штуки, изменяющиеся в IO-контексте, то в чём проблема?
Я говорю про случай, когда к твоим инструкциям нужно добавлять IO-инструкции. У тебя есть стейт и тебе нужно печатать в консоль. Стейт хранится не в IORef-ах, а в StateT. Покажи, как убрать эти чёрные ходы (если их вообще нужно убирать), при этом оставив возможность перемежать твои доменные операции с печатью в консоль.
Бесплатные видеокурсы с задачками на stepik от Дениса Москвина.
Как, блядь, всё это запомнить?!
Вот прямо сейчас заглянул в доке и заменил несколько своих операторов на библиотечные. Доколе?
Ну основные тайпклассы легко запомнить, благо их не очень много и они предельно логичные: Semigroup, Monoid, Functor, Applicative, Alternative, Monad, MonadPlus, Foldable, Traversable.
У них главное помнить про их основные функции и операторы.
Это то, что используется везде и в целом имеет достаточно логичные операторы и логику. Для каждого из них есть ещё куча всяких интересных комбинаторов, но их можно не запоминать, а использовать hoogle и typed holes, чтобы находить их по мере надобности.
Дальше идут всякие MTL типа MonadReader, но в них всё просто и обычно аналогично функциям соответствующего трансформера.
Ещё можно помнить про Arrow и т.п., но комбинаторы оттуда не очень часто используются, так что это на любителя.
Ну и инфраструктурные тайпклассы наверное надо помнить: всякие Coercible, HasField, IsLabel, Generic и т.п. А то на них сейчас в экосистеме очень много всего построено.
> Но если ты не используешь IORef-ы и другие штуки, изменяющиеся в IO-контексте, то в чём проблема?
Проблема в том, что тогда любому умнику работающему в этой код базе ничего не помещает сделать такой ход конём:
myDomainFunction :: MyDomainMonad DomainType
myDomainFunction = do
__doSomething ...
__-- здесь у нас куча бизнесовой логики
__-- а потом какой-нибудь умник вставляет сюда
__runIO launchMissiles
__-- и всё, мы теперь даже никак не узнаем, что у нас тут вообще какие-то unrestricted побочные эффекты
__-- потому что сигнатура функции не поменялась
И нафига нам тогда эрзац система эффектов в виде фри монад, если никакой пользы как система эффектов она не несёт и никакие эффекты не трекает?
Тестируемости ради? Так не проще тогда бегать с рекордами функций и ReaderT паттерном? Оно настолько же тестируемо, только при этом перформанс показывает порядком лучше и не требует бойлерплейта с интерпретаторами и т.п.
Если ты знаешь заранее, и можешь перечислить, какие IO-операции будут вызываться вместе с твоими доменными операциями, можно для этих IO-операций создать отдельную ограничительную монаду, тогда невозможно будет вызвать launchMissiles.
Но если ты заранее не знаешь, какие IO-операции понадобятся вызывающему коду, то такую ограничительную монаду объявить не получится. Но я не вижу в этом проблемы, потому что именно это и нужно написать: нужно дать возможность вызывающему коду вызвать любую IO-операцию, в том числе и launchMissiles. Вызывать launchMissiles или не вызывать - это уже отвественность вызывающего кода, а не твоя.
> тогда невозможно будет вызвать launchMissiles.
Хотя, можно создать инстанс ограничительной монады для IO, и в реализации какой-нибудь операции вызвать launchMissiles, но я думаю такой код будет бросаться в глаза.
Есть ли какой-нибудь способ исключить возможность вызова launchMissiles, но при этом чтобы была возможность вызывать нужные тебе IO-операции?
Короче, получается такой разговор: ты говоришь "IO плохо", я говорю: "да, IO плохо, но оно нужно", потом я спрашиваю "как сделать так, чтобы вызывались только нужные тебе IO-операции?", а ты отвечаешь "IO плохо".
> И нафига нам тогда эрзац система эффектов в виде фри монад, если никакой пользы как система эффектов она не несёт и никакие эффекты не трекает?
Для удобства, плюс эти эффекты могут делать всё что угодно, но если ты не хранишь состояние приложения в IORef-ах, то состояние они не меняют.
Зачем в ORM-ах нужны всякие DSL создания запросов, если там есть функция запуска запроса из строки? Ответ: для удобства.
А если знаешь подход получше, то опиши его.
Хм, их действительно немного. Похоже, у меня проблема не с запоминанием, а с пониманием, что эти операции делают. Я могу воспроизвести по памяти законы, например, для Semigroup, но я не могу понять, как из них следует, что (<>) - это конкатенация списков и ничто другое. Монадами я вообще могу пользоваться в do-нотации. Как вы это понимаете всё?
> Хотя, можно создать инстанс ограничительной монады для IO
Можно создать ограничительную монаду, основанную на IO, сделать так, чтобы она не была тайпклассом и не была инстансом MonadIO. Получается такой список операций, который невозможно расширить, можно только вызывать операции.
>>2004439
> А если знаешь подход получше, то опиши его.
До этого ты упоминал про преимущество таглесс файнал стиля, что можно отличать функции, использующие IO-операций, от тех, которые не используют их. В принципе можно согласиться, но это просто способ отмечать функции, ведь всё равно возможность вызвать launchMissiles не исключается.
Ну да, ты прячешь всё нужные операции за своими тайпклассами, пишешь код как:
myDomain :: (HasDb m, HasPrint m, ...) => m MyType
И дальше реализуешь для своего монадического стэка который на краю приложения в качестве m в такие функции втыкается
> Как в хаскелле обстоят дела с GUI?
Биндинги к GTK, Qt и wxWidgets
> Есть нормальные игровые движки?
Ну движков большого уровня нет, а так кажется, что гонять игры на ленивом языке - это рискованное занятие.
> а так кажется, что гонять игры на ленивом языке - это рискованное занятие.
Получится так, что вся программа это одна большая монада?
Нет, проблема не в этом. Будет много борьбы с тем, что лэтенси нужный для игр стабильно держать.
В данном случае речь про то, что может быть сложно стабильно держать 16 мс на кадр в языке с ленивыми вычислениями и сборщиком мусора.
Нихуя. Лямбда хоть и эквивалентна брейнфаку, но не равна ему. Это принципально разные языки, не нельзя их отнести как подмножества/надмножества к друг-другу.
>подмножества/надмножества
Значение знаешь?
Из хаскеля в брайнфак изоморфизм можно написать. Хаскель подмножество брайнфака, а брайнфак подмножество хаскеля.
Ну давай, напиши source-to-source transpiler из хаскелла в брейнфак, а я погляжу.
Достаточно сделать транспайлер из C- или бакенд для LLVM. И не получится портировать System.IO и прочее.
И то и то полное по Тьюрингу. Я же говорю, вы не представляете как всё плохо на самом деле.
>И не получится портировать System.IO и прочее.
Win32 под линупс написали. А тут какая то библиотека от никому не нужного языка(читай маленькая).
Вы не понимаете, это другое.
В POSIX больше тысячи системных вызовов, в BF-машине - 4, два из которых - это управление потоком выполнения.
(<>) в полугруппе это бинарная операция с типом a -> a -> a, которая чем-то похожа на сложение, только в более широком смысле. Какая функция у нас складывает два списка, получая третий?
Двачую этого господина и хочу поделиться статьей которая как помне хорошо описывает что такое semigroup на интуитивном уровне.
http://www.tomharding.me/2017/03/13/fantas-eel-and-specification-4/
Вообще советую всю серию, хоть примеры в джс, сама суть помогла понять лучше картину алгебраических структур
http://www.tomharding.me/fantasy-land/
Спасибо! А это какого числа версия, я только метку 2018 гор увидел, но полная же позже вышла?
ООП и сабтайпинг это разные вещи. ООП это вообще цирк, не имеющий никаких математических основ.
Поподробней?
>не имеющий никаких математических основ
А вот здесь поподробнее, пожалуйста. Что ещё за "математические основы"? В каком смысле вы используете этот термин? Статический анализ ООП-кода возможен, формальная верификация - тоже. Что вам ещё нужно?
Сама концепция ООП в том виде, что она есть сейчас, - императивщина неверифицируемая. Попробуй статично проанализировать мутирующий в рантайме код, а я погляжу.
То есть "математические основы" - это какой-то ваш собственный термин, а не что-то конкретное.
Как ООП и комерческая успешность связаны? Клиенту похуй, на чем написано. Главное чтобы работало быстро и был красивый UI.
> А что ты скажешь о том простом факте что твой фп-код под капотом превращается в код на императивном C
Не превращается. Ghc не транслятор.
Хаскель никак не использует теорию категорий.
1. Hask не является категорией. Аксиоматика требует, чтобы undefined . id = undefined, однако это не выполняется. Hask похожа на категорию, но является чем-то другим.
2. Понятия из теории категорий не используются в языке. Так, в хаскелле нельзя определить произвольную категорию. Всё рассматриваемое должно быть "подкатегорией" Hask и определяться неявно. Поскольку Hask не является категорией, категорий в языке нет вообще. Аналогично, нельзя определить произвольный функтор. Всё, что есть, - "эндофункторы" Hask. Которые не эндофункторы.
3. Программисты на хаскелле не знают теорию категорий. Я соглашусь, что itt определить категорию более-менее смогут все (впрочем, наверняка забыв про парочку требований). Возможно, смогут определить и функтор, и даже естественное преобразование. Однако сопряженные функторы уже не будут определены. И у меня есть твёрдая уверенность, что ни теорему Фрейда о сопряженных функторах, ни теорему Бека, ни даже теорему Майлейна-Эйленберга о конкретизируемости никто itt не сможет не то что доказать, но даже сформулировать. Ин факт, я думаю, что люди здесь названия этих теорем не слышали никогда.
Производные категории? Локали и фреймы? Превратные пучки? Всё это - базовые вещи теорката - абсолютно не нужно для программирования на хаскелле, абсолютно никак не используется и никогда не упоминается.
Заимствовать несколько стартовых определений (причем по аналогии, а не в точном смысле) - это не то же самое, что использовать теорию категорий. Математическая теория - это про теоремы, а не про определения. Нет смысла в заимствовании определений, если не заимствуются теоремы.
Тут хотя бы методичку Маклейна кто-нибудь прочитал вообще?
https://en.uesp.net/wiki/Shivering:Haskill
Это персонаж в ТЕС Обливион. Ты не знал что в честь тоддоподелия язык назвали?
Потому что чувак несет шизоидную хуйню. Никто не говорит что 1 в 1 код превращается в категории, но идея и многие правила идут оттуда.
Если говорить о функциях, то тогда есть функция (>>=). Синтаксический сахар, использующий (<-) эквивалентен вызовам (>>=).
Лучше бы задал вопрос: «В чем разница между типом и множеством».
Ни в чем.
Класс это тип. А типы в прогоаммировании это представление наивной теории множеств.
Я не совсем о программировании. Категория задаётся как класс объектов + морфизмы + ассоциативный закон. Почему ввели новое слово класс, почему не множество объектов?
> A category C consists of the following three mathematical entities:
> A class ob(C), whose elements are called objects;
> ...
https://en.wikipedia.org/wiki/Class_(set_theory)
Почему натуральные числа нельзя назвать множеством? Там в статье как раз приводится что это не множество, а proper class.
Потому что не все обьекты/морфизмы можно впихнуть в множество. Банальный пример - категория Set. В ней обьекты это все множества, а как известно, множества всех множеств не существует, то придумали классы.
Как я понимаю, только в малых категориях вместо класса может быть множество.
> class of all ordinal numbers
Всё, я понял. Если natural numbers ещё можно назвать set, хотя они и бесконечные, то ordinal numbers это больше чем natural numbers и для каждого бесконечного множества можно иметь бесконечное количество вариантов упорядочиваний.
> а как известно, множества всех множеств не существует
Ахах. Учи математику, чтобы не быть батхертом.
> Если natural numbers ещё можно назвать set, хотя они и бесконечные
В теориях множеств, множества могут быть бесконечными.
Пиздос, как же там всё глубоко оказывается. Теорию множеств порезали в аксиоматике чтобы разрешить парадокс Рассела, который нахер ломает математическую логику и доказывает что истина эквивалентна лжи. Вот то что отрезали от теории множеств, это и есть proper classes.
Это просто прекрасно:
> Most sets commonly encountered are not members of themselves. For example, consider the set of all squares in the plane. This set is not itself a square in the plane, thus it is not a member of itself. Let us call a set "normal" if it is not a member of itself, and "abnormal" if it is a member of itself. Clearly every set must be either normal or abnormal. The set of squares in the plane is normal. In contrast, the complementary set that contains everything which is not a square in the plane is itself not a square in the plane, and so it is one of its own members and is therefore abnormal.
> Now we consider the set of all normal sets, R, and try to determine whether R is normal or abnormal. If R were normal, it would be contained in the set of all normal sets (itself), and therefore be abnormal; on the other hand if R were abnormal, it would not be contained in the set of all normal sets (itself), and therefore be normal. This leads to the conclusion that R is neither normal nor abnormal: Russell's paradox.
Просто человеческий язык слишком гибкий и позволяет придумать такие штуки, которые всё ломают.
А ты отверги эту аксиому и развивай свою. Глядишь чего ещё нового интересного получится.
К примеру, делаю так
myButLast [x,_] = x
myButLast (x:xs) = myButLast xs
evalAndPrint a = putStrLn . show . myButLast $ a
А потом нужна функция двух переменных
elementAt (x:xs) 1 = x
elementAt (x:xs) index = elementAt xs (index - 1)
evalAndPrint a b = putStrLn . show $ elementAt a b
И putStrLn . show . elementAt $ a b уже не работает, потому что оператор композиции имеет тип (.) :: (b -> c) -> (a -> b) -> a -> c Можно конечно ещё написать putStrLn . show . (elementAt a) $ b но это как-то совсем неочевидно.
Что характерно, в первом примере я не могу сделать
evalAndPrint = putStrLn . show . myButLast
Нужно обязательно параметр указать, хотя казалось бы, композиция должна уметь это делать. Возможно просто не хватает явной сигнатуры, но это всё очень неочевидно.
> И putStrLn . show . elementAt $ a b уже не работает
Это ведь означает (putStrLn . show . elementAt) $ (a b), как будто а - функция, принимающая b в качестве параметра.
Какие-то сомнительные примеры. Мне кажется, evalAndPrint без параметра должен компилиться, только лень проверять.
Ну ладно, operator precedence это везде боль, надо привыкать. Но второе не собирается, почему-то ему хочется больше инфы про типы.
Класс - это совокупность каких-то вещей.
Множествами называются классы, которые могут быть элементами других классов.
Собственные классы, или большие классы, - это классы, которые не могут быть элементами других классов.
Например, совокупность натуральных чисел - множество. Совокупность всех множеств - большой класс, но не множество. Подробнее см. в учебнике по NBG.
>>2022291
Mor C - совокупность всех стрелок категории C.
HomС(A,B) - совокупность всех стрелок из A в B в категории C.
Mor - объединение всех Hom'ов.
Малые категории - у которых Mor является множеством.
Локально малые - у которых любой Hom является множеством, но Mor может не являться множеством.
Большие категории - у которых хотя бы один из Hom'ов не множество.
Всякая малая категория также и локально малая, разумеется.
>>2022370
В классических теориях множеств (Z, ZF, ZFC и популярные дополнительные аксиомы для ZF, NBG, MK) совокупность всех множеств не является множеством. В NF и NFU множество всех множеств таки есть, но нельзя доказать, что оно является моделью NFU.
>>2022380
>истина эквивалентна лжи
Из противоречия следует вообще какое угодно утверждение, не только 1=0.
> вообще какое угодно утверждение
Если быть точным, то из него следует неконсистентность теории.
Именно любое утверждение. Пусть доказаны A и ¬A, и пусть B - произвольное утверждение.
1. A # по условию
2. ¬A # по условию
3. ¬A→¬A∨B # аксиома
4. ¬A∨B # Modus Ponens к 2 и 3
5. ¬A∨B ⇔ A→B # известная теорема об импликации
6. A→B # MP к 4 и 5
7. B # MP к 1 и 6
чтд
Эти пункты - логический вывод в обычном исчислении высказываний. В выводе каждый пункт должен быть либо аксиомой, либо ранее доказанной теоремой, либо получаться из каких-то предыдущих пунктов по правилу Modus Ponens. Правило Modus Ponens (MP): если выведены утверждения X и X→Y, то следует считать выведенным утверждение Y.
Значок ¬ означает "не". Пункты 1 и 2 - обнаруженное противоречие. Значок ∨ означает "или". Пункт 3 - логическая аксиома: какими бы ни были утверждения X и Y, следует считать выведенным утверждение X→X∨Y. В качестве X взято утверждение "не A", в качестве Y - пока что не доказанное утверждение B.
Значок → означает импликацию, связку "если ... то ...". Пункт 5 - теорема об импликации. Теорема говорит, что утверждение "¬A∨B" эквивалентно утверждению "A→B". Убедиться в справедливости теоремы можно, сравнив таблицы истинности для этих двух утверждений.
6 и 7, наверное, понятны.
Например, пусть A - "небо синее", ¬A - "небо не синее", B - "луна сделана из сыра".
Тогда вывод будет следующим.
1. Небо синее
2. Небо не синее
3. Если небо не синее, то небо не синее или луна сделана из сыра.
4. По п.2 небо не синее, и имеем: небо не синее или луна сделана из сыра.
5. То, что небо не синее или луна сделана из сыра, равносильно тому, что: если небо синее, то луна сделана из сыра.
6. Итак, если небо синее, то луна сделана из сыра.
7. По п.1 небо синее, и имеем: луна сделана из сыра.
Самый неинтуитивный момент здесь - эквивалентность ¬A∨B ⇔ A→B.
Дело в том, что утверждение "если A, то B" ложно лишь в одном случае: когда A истинно, а B ложно. А во всех остальных случаях это утверждение истинное, что и даёт эквивалентность. При этом между A и B может не быть никакой смысловой связи. Если интересно, почему так получилось, то можно посмотреть учебник матлогики или статью https://ru.wikipedia.org/wiki/Парадокс_импликации
>>2023350
Спасибо, теперь понятно. Да, действительно, теорема об импликации - неинтуитивная штука. Но, с другой стороны, противоречия тоже неинтуитивны, хотя может быть бывают разные уровни интуиции, и на каком-то уровне интуиция признаёт противоречия и бессилие разума перед ними. Только куда дальше двигаться с этой точки? Релятивизм? Придумывать себе свою субъективную истину?
Если в теории найдено противоречие, то теорию нужно выкинуть и сделать новую теорию. Заменить одну какую-нибудь аксиому или вообще все.
> Из противоречия следует вообще какое угодно утверждение, не только 1=0.
В общем-то говоря, если мы скажем в Wolfram Mathematica или в Prolog'e, что
1 = 0, то это будет истиной, а обратное - ложью.
Можно сказать, что 1 + 2 = 4, и это будет одной из бесконечного множества алгебр.
Математика это наука об абстракциях, здесь нет ничего априорного, кроме редукции и эквивалентности.
Не удивлюсь, если в будущем найдут что-то, что через подобные базисы можно описать.
> Речь шла не об арифметике
Я клоню к тому, что единственными аксиомами в математике являются равенство и эквивалентность (она же редукция), потому что у них нет определения. У все остальное определяется через эти две аксиомы.
> ⊤⇔⊥
Мы вправе объявить "всё = ничто", однако тогда может оказаться ложными множество полезных для нас теорий.
Возможно, тебе стоит прочитать хотя бы парочку учебников матлогики.
Отвечаю на свой пост. Я написал:
> Но, с другой стороны, противоречия тоже неинтуитивны
и ещё про
> противоречия и бессилие разума перед ними
а потом задумался: действительно ли противоречия неинтуитивны? Может наоборот? Человек мыслит противоречиво, это только потом, в какой-то момент, он узнаёт, что есть логика, что противоречия - это как бы плохо и их нужно устранять, но это просто тонкий слой какой-то культурной надстройки, а под этим слоем кроется противоречивое и парадоксальное подсознательное мышление. Да даже этот слой не мешает людям в противоречивые параграфы.
>Hask не является категорией. Аксиоматика требует, чтобы undefined . id = undefined, однако это не выполняется. Hask похожа на категорию, но является чем-то другим.
Разумеется, как и в любом тьюринг-полном языке, в Хаскеле любой тип - это не просто тип, а тип + ⊥. Т.е. жопа встроена в Int, в Bool, в небо и даже в Аллаха. Это ломает базовую аксиоматику.
Жопу из семантики тьюринг-полного языка просто так не выкинуть. Для этого, как минимум, потребуется гарантировать остановку, что автоматически сделает язык не тьюринг-полным.
Но является ли это чем-то плохим? На практике, ты не захочешь, чтобы твоя программа вычисляла жопу. Если твоя программа попробует её вычислить, она любо пизданётся с исключением либо зависнет. Т.е. любая корректная программа работает c Hask именно как с категорией.
То, что Hask, строго говоря, не является категорией на уровне семантики языка, то уж извини, это плата за тьюринг-полноту. GHC - не Б-х, он не сможет отсечь все некорректные программы, одновременно оставив возможность написать любую корректную. Это просто инструмент, тут правильнее говорить о том насколько он близок к идеалу по сравнению с другими инструментами, понятное дело, в полном смысле он никогда не будет идеальным.
<interactive>:113:1: error:
• No instance for (Semigroup Integer) arising from a use of ‘<>’
Почему целые числа не образуют полугруппу в хаскеле?
Потому что можно придумать много полугрупп над полем целых чисел. Ты какую полугруппу хочешь? Min, Max, Sum? В Хаскеле все они есть, можно и свою определить, если библиотечных не хватает.
Почему тогда списки/строки имеют некий дефолт в Semigroup? Разве там нельзя придумать альтернативный оператор?
Поэтому хаскель не использует теорию категорий. Используется что-то, что похоже на теорию категорий, но не является теорией категорий. Что именно - большой вопрос. Образования вроде Hask в теоркате не встречаются.
>>2025138
Ещё тебе нужно узнать, что такое естественное преобразование ака функторный морфизм. Морфизмы категории эндофункторов - естественные преобразования.
Моноид в категории эндофункторов - не то же самое, что моноид. Моноид в обычном смысле - это непустое множество с ассоциативной бинарной операцией ×, у которой есть нейтральный элемент.
А моноид в категории эндофункторов C получается следующим образом. Во-первых, множество заменяется на функтор T:C→C; о точках множества, таким образом, перестают думать. Во-вторых, композиция заменяется некоторым естественным преобразованием из T×T в T, здесь T×T = T2 - двукратное применение функтора T. В-третьих, нейтральный элемент заменяется некоторым естественным преобразованием из 1C в T, здесь 1C = id C - тождественный функтор для C. Во множестве M нейтральный элемент можно выделить с помощью отображения из 1 в M, где 1 - одноэлементное множество; в определении моноида в категории происходит нечто похожее. Наконец, на эти два естественных преобразования накладывается условие: должны быть коммутативны диаграммы пикрелейтед. Выражающие суть ассоциативности и нейтрального элемента.
Извозчик довезёт.
Можно, наконец, выкинуть "паттерны" вроде Factory вместе с остальными достижениями индусов из области набора латиницы на клавиатуре и использовать простые и понятные для нормального человека понятия, вроде тайпклассов.
>Только куда дальше двигаться с этой точки?
к диалектике логикам устойчивым к противоречию офк
https://en.wikipedia.org/wiki/Paraconsistent_logic
А зачем? Классической первопорядковой логики предикатов хватит всем, нет причин вводить искусственные костыли ради сохранения противоречий. Противоречия можно просто устранять.
> А вот здесь поподробнее, пожалуйста. Что ещё за "математические основы"?
Это когда ты рассматриваешь код как некую математическую формулу из некоей формальной теории и рассуждаешь о нём, используя математический аппарат.
В ОО языках эта формальная теория придумана с нуля безграмотными слесарями и описана выражениями вида "Return centered in a string of length width. Padding is done using the specified fillchar (default is an ASCII space). The original string is returned if width is less than or equal to len(s).", к которым проще применять не математический аппарат, а эмоциональный.
Теория от слесарей конечно хуже, но тоже вполне работает. Самое главное она легко понятна другим слесарям. Обучение вполне вписывается в поток и всё познаётся от простого к сложному. Суперабстракции нужны только через год-два практики.
А в хаскеле ты просто сразу на хуй с порога идёшь разбираться с теорией категорий, просто потому что много концептов в языке решили назвать терминами оттуда по аналогии. Сюда же накладывается сложная система типов, само по себе ФП где всё наизнанку вывернуто и компилятор/рантайм по сути перекручивают AST туда-сюда вместо явной последовательности действий. Даже стека вызовов нет.
Несмотря на обилие книг, статей, на обширную вики и кучу ответов на SO, в хаскеле до сих пор нет нормального туториала от простого к сложному, включая нормальное объяснение нахуя козе баян в виде всех этих категорий монад и функторов. Вот только здесь более-менее поясняется https://www.haskellforall.com/2012/08/the-category-design-pattern.html
> идёшь разбираться с теорией категорий
На самом деле нет, именно с теорией категорий разбираться вовсе не нужно. В том смысле, что бесполезно скачивать учебник теорката и читать его, большинство информации из такого учебника не пригодится. Из теории категорий в хаскеле только категория, морфизм, функтор, естественное преобразование, монады, сопряжения, алгебры, категория Клейсли и формализация лямбда-исчисления, никаких сложных определений и никаких теорем. Причем реально большинство людей дальше функторов по этой цепочке не продвигаются. А какой-нибудь zygohistomorphic prepromorphism - внутренний мем хаскеля, в теории категорий таких штук нет.
Курс на степике нормально базу дает че ты епта
С хаскелиста-штангиста, живущего с мамкой
С хаскелиста, который засовывал себе штангу в зад
1280x720, 0:23
> (потому что моноид с операцией сложения, такого, например не содержит)
С хуя ли не содержит?
data Nat = S Nat | Z
S x + y = x + S y
Z + x = x
x + Z = x
Т. е такой, что при аппликации к нему, (вне зависимости от остальных аргументов) возвращается он сам?
x Z = Z
Z x = Z
Тащемта можно создать обобщонную функцию, которая выражает все подобные функции над любым количеством аргументов.
Всегда пожалуйста, анон.
Дефолтным является самый распространённый юзкейс (конкатенация)
Над целыми числами просто нет явного «дефолтного» юзкейса
Какой выберешь, сложение или умножение?
Не совсем.
>Т. е такой, что при аппликации к нему, (вне зависимости от остальных аргументов) возвращается он сам?
Тащемто да.
>Тащемта можно создать обобщонную функцию, которая выражает все подобные функции над любым количеством аргументов.
Тут бы хотелось попадробнее. Есть задача - организовать раннюю остановку программы и выразить это красиво математически. В некоторых случаях абсорбирующий элемент моноида для этого подходит. Например, мы вычисляем a & b & c & d & e.. В какой-то момент мы поняли, что выражение стало равно false, это значит, что дальше вычислять не имеет смысла, потому что всё равно стало false и при дальнейшем примерении операций false так и останется.
Но есть одна проблема.
x Z = Z
Z x = Z
подразумевает, что Z - единственный. Т.е. что Z = Z. Но у меня задача - поиск кратчайшего пути в графе. Т.е. если я нашел кратчайший путь, я могу останавливать алгоритм и выводить результат, другой путь будет точно не короче. Поэтому, в плане длинны, они эквивалентны. Но они не равны друг другу.
Это не один абсорбирующий объект, это класс объектов. Пользователю похуй какой путь найдёт программа, ему любой путь подойдёт. Но и "забывающее" отображение применить нельзя, потому что пользователю интересен сам путь, а не его длинна, которая могла бы "забыть" маршрут и уровнять все пути через их длину. Вот я думаю, можно ли эту логику впихнуть в моноид какой-нибудь.
Лучше сделай сайт на Node.js. Нахуй тебе сайт на Хаскеле, ты наебёшся по всем фронтам, начиная с хостинга, кончая программированием. Хаскель никогда не был в топчике для лепки сайтов.
Лучше сделай сайт на PHP. Нахуй тебе сайт на Node.js, ты наебёшся по всем фронтам, начиная с хостинга, кончая программированием. Node.js никогда не был в топчике для лепки сайтов.
Nginx (и вообще веб сервер) удобнее, потому что он может заниматься специфическими веб вещами и существует отдельно от твоего приложения и конфигурируется тоже отдельно.
Плюс если тебе понадобится добавить в сайт что-то отдельное от твоего хаскель приложения, то тебе понадобится веб сервер.
> Тут бы хотелось попадробнее
Ну смотри. Пусть absorb - обощенная функция, такая, что при применении к ней абсорбирующего элемента Z она возвращает Z.
Тогда такие операции как () и (&) можно выразить через эту функцию:
() = absorb 0
(&) = absorb False
✨ Магия✨
Не знаю, как в хаскелле, но в JS эту обощенную можно написать так:
let absorb = x => fn => (...args) => args.find(x) && x || fn(...args)
and = absorb (false) (() => true)
and(true, true, false)
Кстати да. На PHP еще лучше. Он специально для этого разрабатывался.
На node.js хорошо лепить браузерные приложения на react+material-UI или аналогах. Он хорош, если планируется сделать сложное веб-приложение с множеством функций. Но если сайт простой, на PHP слепить быстрее.
>>2034820
Вообще похуй. К тому времени, как вопрос производительности встанет ребром, ты уже 20 раз перепишешь свой сайт.
На Хаскеле сайт тоже будет тормозить, когда речь зайдёт о хайлоаде. Вернее, придётся специально ебаться чтобы там всё оптимизировать нужным образом. Скорее всего, код будет многократно переписан. Поэтому самое правильное решение - взять готовую cms-ку и слепить на ней сайт за вечер. А проблемы решать по мере их поступления.
Не, это, похоже, чтобы отменять операцию полугруппы. Кстати, выглядит как клёвая абстракция для онлайн-процессинга. У нас была база данных для рассчета стоимости портфеля в реальном времени. Что-то типа SQL, но мы как-бы не селектили, а создавали запрос, который "висел" в памяти и реагировал на изменения исходных данных. Когда прилетал апдейт какой-нибудь позиции, групповые операции не выполнялись повторно, а применялась разница. Так как групповые операции - суть свёртка по моноиду, возможно это подходящая абстракция, чтобы выкидывать из результата свёртки устаревшие элементы и заменять их новыми.
А как мне логировать отдельные чистые функции? Ну типа отдебажить? Я же не могу посреди чистой функции написать что-то типа "console.log(x)".
>А как мне логировать отдельные чистые функции
Зачем их логировать? Доказывай их
форсим пруверов тред как можем
Анон, прошу прощения. Это походу не книга Брагилевского, а что-то другое. Я не знаю почему файл так называется, но это скорее всего не Haskell in Depth.
Хотя я сейчас понимаю, что скорее всего во взрослых структурах данных Text, ByteString, во всяких array наверное этого нет, как и в питоне.
У нас рекурсивные схемы
Здесь другой подход. Вместо списка действий задаётся некое выражение в виде дерева, которое нужно отредуцировать. И чтобы это дерево не разрасталось бесконечно применяются всякие tail call optimizations, shortcut fusion, то есть компилируется всё уже в привычные циклы. При этом мощность абстракций получается намного выше любого языка с циклами. Там где ты пишешь километровые дженерики с макросами после обработки исходноков sed'ом, мы продолжаем писать на обычном простом хаскеле.
Почитал тред так вообще охуел, какие-то фри монады, теглесс, линзы.
Я хочу просто лампово поиграться с приятным ФП вечерами, планирую делать пошаговую текстовую игру.
Я чисто на книге выеду с такой задачей?
>Я чисто на книге выеду с такой задачей?
Можно и без линз и теглесс.
Эти вещи немного облегчают жизнь и всё.
Монада — один из типов (определённых конвенционально), которому могут соответствовать данные в контексте интерпритации этих данных тайпкласс системой
Соответствие данных тайпкласс системы является таким же, как и соответствие числа 7 одновременно двум категориям: простым числам и нечётным числам
Нет, он может быть монадой или функтором например
Template Haskell, по-видимому.
> Во-первых, на Хаскеле за деньги никто не пишет.
Как так? Ну не могут же все прогеры только на джаваскрипте фронтенд писать, наверняка и на хаскель пишут, раз вакансии на хх.ру и линкедине есть.
> Вообще, все нормальные люди наоборот донатят на развитие Хаскеля, потому что приколоться за язык хочется, но самому его развивать по понятным причинам лень. Воспринимай Хаскель как сорт оф сообщества стримеров, которые производят интересный контент.
Т.е. хаскелль как ардуино - имеет большое сообщество, но на практике используется редко?
Молодес какой
Ну бери и пиши
Ленивость
Списки идеально вписываются в парадигму хаскеля, массивы не вписываются начиная от мемори менежмента и заканчивая конечным интерфейсом, ломающим абстрактные иммутабельные копии
Хуже фсярпа нет
> Понятия из теории категорий не используются в языке. Так, в хаскелле нельзя определить произвольную категорию.
"Гусь в воде, следовательно, он фиолетовый."
Типичный математик харкача.
elementAt :: [a] -> Int -> a
myButLast :: [a] -> a
putStrLn . show $ elementAt a b
=
putStrLn (show (elementAt a b))
а вот
putStrLn . show . elementAt $ a b
=
putStrLn (show (elementAt (a b)))
Это, очевидно, не то, что ты хотел бы.
Во-первых, если хочешь композировать, то неплохо бы сразу порядок параметров определять заточенным под это (поучись у библиотеки base этому):
elementAt :: Int -> [a] -> -> a
myButLast :: [a] -> a
evalAndPrint n = putStrLn . show . elementAt n
А вот эта evalAndPrint = putStrLn . show . myButLast штука должна нормально компилироваться, вообще-то.
> А вот эта evalAndPrint = putStrLn . show . myButLast штука должна нормально компилироваться, вообще-то.
Посмотрел, действительно ambiguilty компилятор видит. Баг по-видимому.
Матаношиз, протеки обратно в свой загончик, тебе тут не рады.
Ogo
Не надо говорить "моноид" подразумевая "какую-то алгебраическую структуру".
Моноид - это моноид.
Самое ближайшее по описанию, название чего мне известно - полугруппа с нулём.
И еще, нигде не говорится, что этот 0 (как и id) должен быть единственным.
> Не надо говорить "моноид" подразумевая "какую-то алгебраическую структуру".
Не бывает ничего, кроме структур. Всё есть структура. Языков программирования это тоже касается.
•w•
> Всё есть структура
Но не всё есть моноид жи. Не всякая алгебраическая структура есть моноид.
Моноид - это вполне определенная алгебраическая структура, обладающая вполне определенными свойствами.
Описывать все алгебраические структуры через видоизмененный моноид, это как:
"Citroen C5, но от Renault, с другим салоном и желтый, ..."
"а вот это - Citroen C5, но от больший, с прицепом и от концерна MAN, предназначенный для перевозки тяжелых грузов на тысячи километров, ..." (фура)
"это Citroen C5, но с тяжелобронированный, с башней, гусеницами, более мощным двигателем, ..." (танк)
> Хаскель реально требует больших умственных усилий чем какие-нибудь кресты, го
Только первое время. И вообще нужно развиваться комплексно, и выучить Prolog и Haskell. Потом сможешь писать интерпретаторы Пролога на Хаскелле, и Хаскелла на Прологе. После этих двух языков начнешь смотреть на мир программирования иначе, это я тебе гарантирую.
> После этих двух языков начнешь смотреть на мир программирования
как на говно.
Так что лучше забей, а то сопьёшься потом.
> как на говно.
Факт. После Lisp, Haskell, и Prolog ты начнешь презирать ООПетухов, императивщиков, и прочих униженных макак.
Есть Art of Prolog, но сам я его учил по туторам в интернете и практикам в хеллоувордах пока не осознал, как работает Prolog и достиг просветления.
с чего ты решил что у тебя они прямые?
Ну, если говорить про мутабельность, то в конечном счете, от неё не избавиться. Даже если мы создадим pure-functional компьютер в основе которого лежит низкоуровневый Thue language, нужно всё равно имплементировать в компьютер систему перезаписи, что уже есть мутабельность по своей сути.
>Ну, если говорить про мутабельность, то в конечном счете, от неё не избавиться.
Кто-то пытается от неё избавиться?
На. Под кроватью живу я
Макаки, высирающие парграфы ни то жира, ни то непонимания общих концептов ФП
Каждый бля тред
Это уже на другом уровне абстракции, похуй.
Нет, наоборот кресты и го заставляют тебя держать в голове кучу всякого ебанутого говна. А если ещё и динамикопараша — то вообще можно свихнуться.
Пьюрити и иммутабельность не то, чтобы про особенности реализации, так что возможно тебя обманули, или ты просто не так их понял.
Чистый код на каком-нибудь хачкеле в рантайме мутирует память, но при этом там иммутабельность. Think about it.
foo = print "Hello World!" :: IO ()
Это чистый код в одном понимании, и грязный код. В другом.
В первом понимании грязный код был бы
foo = print "Hello World!" :: ()
Т.к. скрывает сайд эффект/применяет его мгновенно, а не описывает его в виде структуры данных.
во втором понимании чистый код был бы
foo = () :: ()
Т.к. он (честно) не работает с IO, а значит чистый
Как и в этом случае, когда речь об иммутабельности, что именно под этим подразумевается зависит от контекста.
Тред сдох? Не догоняю что ставить, platform или stack. Вроде platform содержит стэк. Зачем тогда ставить отдельно стек и зачем нужен платформ если все равно нужен стек?
>Тред сдох?
Нет, мы просто ленивые
>Не догоняю что ставить
Спутник V
>зачем нужен платформ если все равно нужен стек
Кто знает, что ему нужно, тот и поставит что нужно. Не знаешь - ставь платформ и постигай азы хаскеля, а не его энвайромента
>Не знаешь - ставь платформ и постигай азы хаскеля, а не его энвайромента
Что? Мне не нужны лишние абстракции.
>Кто знает, что ему нужно, тот и поставит что нужно.
На сайте хаскеля могли бы и написать в чем разница между платформ и стек. Судя по всему сообщество хаскеля это много о себе мнящие бездельники.
>Мне не нужны лишние абстракции
Что ты в треде про хаскелл забыл?
>На сайте хаскеля могли бы и написать в чем разница между платформ и стек.
Что такое стек и что такое платформ там написано какбэ.
>Что ты в треде про хаскелл забыл?
То есть Хаскел про лишние абстракции? Только у кого руки кривые.
>>2117913
>Спутник V
Более 60% сотрудников завода, производящего «Спутник V» в Уфе, отказались вакцинироваться
https://www.business-gazeta.ru/news/515951
ВОЗ нашла нарушения на производстве «Спутника V» в Уфе
https://www.kommersant.ru/doc/4868950
Согласно Нюрнбергскому кодексу: Абсолютно необходимым условием проведения эксперимента на человеке является добровольное согласие последнего.
>Спутник V
Еще кое что вспомнил. Россия как и СССР не запатентовали ни одного лекарства с доказанным положительным эффектом и доказанной безопасностью.
>То есть Хаскел про лишние абстракции? Только у кого руки кривые.
Так если не кривые, то проще на крестах писать.
>Более 60% сотрудников завода, производящего «Спутник V» в Уфе, отказались вакцинироваться
>ВОЗ нашла нарушения на производстве «Спутника V» в Уфе
Вот и сотрудников с некривыми руками не нашлось.
>Согласно Нюрнбергскому кодексу: Абсолютно необходимым условием проведения эксперимента на человеке является добровольное согласие последнего.
Ты и так и так участвуешь в эксперименте. Зачем ты притащил какой-то кодекс, руки что-ли кривые?
>Вот и сотрудников с некривыми руками не нашлось.
Почитай какие нарушения на этом производстве нашли и видео посмотри. Сами производители отказываются колоть в себя бадягу, которую производят.
>Ты и так и так участвуешь в эксперименте.
Не надо за всех говорить. Я не участвую.
А еще почитай и посмотри видео факты как подменяют прививки. Подписываешься на Спутник, а получаешь неизвестно что. Они даже шифроваться не будут, в сертификате будет что угодно, но не Спутник.
Stack. Платформа - это просто какая-то странная сборка с компилятором и несколькими тулзами, которая появилась задолго до стека и существует по историческим причинам. Но если ты устанавливаешь Stack, он и так доставит всё, что нужно.
>Хаскель реально требует больших умственных усилий чем какие-нибудь кресты, го?
За Го не скажу, не писал на нём. Но на Хаскеле точно легче программировать, чем на крестах. Кресты - это вообще отдельное искусство. Да сам подумай логически, нахуй нужен высокоуровневый язык, если на нём программировать сложнее, чем на крестах?
У Хаскеля есть некоторые заёбы в виде высоковатого порога вхождения, но на самом деле это иллюзия. Может показаться, что на крестах проще начать что-то писать, но чтобы научиться хорошо программировать на крестах, нужно затратить гораздо больше усилий.
Да в Хаскеле нет никакого "избавления от мутабельности". Там наоборот её первоклассной сделали. Если в большинстве языков на мутабельность закрывают глаза, мол, есть какие-то переменные, они как-то там мутируют, но ты сам с этим разбирайся, то в Хаскеле для мутабельности ввели специальные конструкции, типа IO и ST. А продвинутый Хаскель - это вообще линейные типы constrained monads, где можно описывать, из какого именно состояния в какое твоя программа будет мутировать.
Хаскель, считай, DSL для описания мутабельности. Ну о чем говорить, если точка входа в Хаскель - это main :: IO (). Т.е. самая главная функция в Хаскеле - это что-то, что изменяет внешний мир произвольным способом. Этот факт прямо в сигнатуре функции отражен, максимально явно.
Я бы не писал "моноид", если бы не имел ввиду моноид. +я бы хотел дополнить его дополнительными свойствами. И это не ноль полугруппы. Но ладно, забей.
> Не надо говорить "моноид" подразумевая "какую-то алгебраическую структуру".
Тащемта, всё есть алгебраическая структура. Если что-то есть, значит это можно выразить в виде структуры.
мимо конструктивист
Я полностью отрицаю то, что математика это не система перезаписи символов. Математика это система перезаписи одних символов другими символами. Не более.
> моноида
Если моноид является математической абстракцией, то его можно представить в виде структуры.
Дружище, читай написанное буквально.
Я говорю, что из "а является б" не следует "б является а", а ты мне раз за разом пишешь, что "а является б", будто это как-то отрицается.
Блядь, каких только долбоебов полна доска. Импликация это не то же самое, что эквивалентность, говна кусок. Ворона это черная птица, ок? Но это не значит, что любая черная птица - ворона.
Ты четко сказал "является". Сказал бы "X есть подмножество Y" вопросов бы не было.
Я не он, лишь прихуел от твоего невежества. "Является" это именно импликация, смотри еще раз про ворону: ворона является черной птицей, черная птица же не обязательно является вороной.
"Является" - многозначное слово.
Так с этим вроде и так никто не и спорит. Конструктивисты только запрещают некоторые виды перезаписи символов, вроде доказательства от противного. Или я вас с кем-то путаю?
Хаскль жив?
Что вообще пишут на хаскеле?
Почему я вообще не могу читать код на хааскеле? Даже Си выглядит лучше
В чем меметичность языка?
У кого больше яйца: у хаселя или лиспа?
осторожно, графомания, но отвечу развёрнуто
>Зачем нужно учить хаскель?
На Хабре есть куча статей о том, какой язык программирования следует учить. Там авторы растекаются мыслью по древу кто во что горазд, но из крайнего, что я читал, мне понравилось наблюдение некого автора (разумеется, я не сохранил ссылку, но это было показательно). Мол он, автор, знает много языков программирования, а его знакомый 20 лет пишет на С++ и ничего другого не знает. Но востребованы они на рынке примерно одинаково.
Т.е. вопрос, сводится к тому, какие ты преследуешь цели? Найти работу? Ну так анализируй рынок. Может быть тебе нужен 1С, кто сказал, что хороший программист на 1С не востребован или чем-то хуже? А может быть тебе вообще не надо заниматься программированием, может тебе лучше стать крутым парикмахером и зарабатывать больше каких-то там программистов, ну если ты реально крутой парикмахер.
Тем не менее, я думаю, если тебе интересно, чтобы IT развивалась быстрее как отрасль, тебе следует учить разные языки программирования. Это касается не только Хаскеля, в принципе следует изучать любые новые языки и технологии. Это напрямую связано с прогрессом, внедрением технологий и решением проблемы "замкнутого круга".
Проблема эта может быть описана так. Очевидно, что любая технология создаётся в какой-то момент времени, исходя из текущих задач и знаний, которыми мы в этот момент времени обладаем. Потом у нас появляются новые знания и кто-то предлагает более совершенную технологию. Но она не может быть внедрена мгновенно, поскольку нет специалистов, следовательно, она остаётся невостребованной, а раз она не востребована, то и новые специалисты не особо мотивированы её изучать. В итоге мы сидим на старых технологиях просто в силу инертности, хотя они могут быть не так эффективны. Но если ты и другие люди вложатся в изучение некой технологии, она может быть внедрена гораздо легче.
Поэтому для ответа на вопрос, зачем тебе учить Хаскель, сначала реши, а нравится ли тебе Хескель? Хотел бы ты на нём программировать? Если бы хотел, то учить его, безусловно, нужно. Ведь с каждым новым программистом на Хаскеле, возможность его применения будет только возрастать. Если тебе пофиг, или если ты хочешь, чтобы какой-то другой язык развивался, то инвестировать своё время в Хаскель не стоит, ну или стоит только ради того, чтобы спиздить из него какие-то приёмы, и внедрить их в язык, который тебе более по душе.
осторожно, графомания, но отвечу развёрнуто
>Зачем нужно учить хаскель?
На Хабре есть куча статей о том, какой язык программирования следует учить. Там авторы растекаются мыслью по древу кто во что горазд, но из крайнего, что я читал, мне понравилось наблюдение некого автора (разумеется, я не сохранил ссылку, но это было показательно). Мол он, автор, знает много языков программирования, а его знакомый 20 лет пишет на С++ и ничего другого не знает. Но востребованы они на рынке примерно одинаково.
Т.е. вопрос, сводится к тому, какие ты преследуешь цели? Найти работу? Ну так анализируй рынок. Может быть тебе нужен 1С, кто сказал, что хороший программист на 1С не востребован или чем-то хуже? А может быть тебе вообще не надо заниматься программированием, может тебе лучше стать крутым парикмахером и зарабатывать больше каких-то там программистов, ну если ты реально крутой парикмахер.
Тем не менее, я думаю, если тебе интересно, чтобы IT развивалась быстрее как отрасль, тебе следует учить разные языки программирования. Это касается не только Хаскеля, в принципе следует изучать любые новые языки и технологии. Это напрямую связано с прогрессом, внедрением технологий и решением проблемы "замкнутого круга".
Проблема эта может быть описана так. Очевидно, что любая технология создаётся в какой-то момент времени, исходя из текущих задач и знаний, которыми мы в этот момент времени обладаем. Потом у нас появляются новые знания и кто-то предлагает более совершенную технологию. Но она не может быть внедрена мгновенно, поскольку нет специалистов, следовательно, она остаётся невостребованной, а раз она не востребована, то и новые специалисты не особо мотивированы её изучать. В итоге мы сидим на старых технологиях просто в силу инертности, хотя они могут быть не так эффективны. Но если ты и другие люди вложатся в изучение некой технологии, она может быть внедрена гораздо легче.
Поэтому для ответа на вопрос, зачем тебе учить Хаскель, сначала реши, а нравится ли тебе Хескель? Хотел бы ты на нём программировать? Если бы хотел, то учить его, безусловно, нужно. Ведь с каждым новым программистом на Хаскеле, возможность его применения будет только возрастать. Если тебе пофиг, или если ты хочешь, чтобы какой-то другой язык развивался, то инвестировать своё время в Хаскель не стоит, ну или стоит только ради того, чтобы спиздить из него какие-то приёмы, и внедрить их в язык, который тебе более по душе.
Почему я смотрю на хаскель и лисп (в лиспотреде такой же пост) тут две причины: я ищу наименее зашкварный ЯП, который не подвержен фемкам и пидорам, а еще я хочу больше углубить знания фунциональщины, поскольку процедурщину я хорошо понимаю. Я разделяю мнение о том, что язык вторичен и первостепенным является область решаемой задачи, так, я не буду писать на питоне для ардуины, а использую Си. Однако в вопросе зашкварности мы абстрагируемся от этого и более обращаем внимание на влияние сомнительных личностей на развитие языка. Вероятно, справедлива корреляция популярности языка и его зашкварности, но я хочу найти баланс популярности и широты спектра решаемых задач для данного ЯП.
Спасибо за развернутый ответ
>Хаскль жив?
Очень даже жив. Если ты посмотришь на графики релизов, роадмапы, динамику развития, то увидишь, что по этим параметрам он уделывает почти всех. Более того, в этом плане он показывает феноменальную стабильность. Меня больше удивляет, за счет чего он жив? Т.е. он как-бы никому не нужен, на нём особо не пишут коммерческих проектов. Тем не менее, за счет чего-то он остаётся одним из самых продвинутых языков.
А стабильности выхода релизов можно только позавидовать. Но вот его востребованность не растёт. Хаскель - какая-то охуенная и безумно интересная игрушка, которая уже лет 20 развивается со стабильностью, которую не могут достичь даже коммерчески успешные проекты, но, при этом, он остаётся игрушкой для небольшого общества фанатов.
По всем правилам, любой подобный язык должен был бы сдохнуть. А Хаскель не дохнет и вообще живее всех живых. В этом его феномен.
>Что вообще пишут на хаскеле?
Очень мало пишут.
Как бы Хаскель настолько крут, что на нём можно писать что угодно. Можно писать крутые веб-фреймворки. Ни в одном другом языке не было столько фишек, чтобы можно было писать настолько крутые веб-фреймворки. На Хаскеле можно статически проверять ссылки, оптимизировать рутинг, встраивать DSL-ы не меняя сам язык. Но, как показала практика, народ пишет сайты на убогом PHP и JNode.
Можно делать крутые DSL-ы для программирования железа, языки программирования FPGA (Haskell Lava), программирование видеокарт (Haskell Accelerate), распределённые вычисления (Cloud Haskell), но ничего из этого не взлетело.
Это другой феномен Хаскеля. Все понимают, что он очень крут. Но почему-то для программирования видеокарт адаптируют Си, и эта адаптированная версия Си взлетает, а Хаскель так и остаётся не более, чем источником идей для этой самой адаптированной сишки, но не языком, который бы применяли на практике.
Из более-менее успешных проектов мне известен лишь Pandoc. Но то, что Pandoc написан на Хаскеле - это скорее историческая случайность. Я уверен, его бы можно было бы на какой-нибудь джаве переписать, просто нет такой необходимости.
>Из более-менее успешных проектов мне известен лишь Pandoc
Много слышал про xmonad A Tiling Window Manager. Преследует философию suckless, т е буквально пересобираешь программу из исходников, чтобы она работала по-другому, по сути меняешь конфигурацию, где конфигурационными файлами является исходный код
>Почему я вообще не могу читать код на хааскеле? Даже Си выглядит лучше
Привычка к синтаксису, не более. Большинство современных языков имеют Си-подобный синтаксис. Поэтому, на первый взгляд, он выглядит более знакомым и понятным. Но это лишь иллюзия. Я - профессиональный программист на Scala. У Scala тоже Си-подобный синтаксис. Но если бы профессионально поработал со Скалой и с Хаскелем, то быстро бы понял, что у Хаскеля синтаксис куда проще и понятнее, чем в Скале. А в Агде он еще круче, в Агде вообще самый крутой синтаксис, из всех, которые я видел.
Алсо, я преподавал языки людям, которые не имели опыта программирования. И Scala там сосала. Очень быстро всплывали все её синтаксические косяки. Но бизнесу не интересны стерильные программисты. А если программист не стерилен, т.е. уже научился Сишке в универе и привык к её синтаксису, то он выберет более знакомый синтаксис, а не более эффективный.
Из этого наблюдения я сделал лишь один вывод - синтаксис не рулит. Ты можешь придумать язык с крутым синтаксисом, но это не даст ему ощутимых преимуществ.
>В чем меметичность языка?
Там нет никакой математичности. Просто позаимствовали названия паттернов из теории категорий. Но это было успешное заимствование, на мой взгляд.
>У кого больше яйца: у хаселя или лиспа?
У Лиспа больше. Лисп - это полная анархия. Из Хаскеля пытаются стоить что-то более структурированное и коммерчески применимое. Но оба языка пока годятся только на мемы и на изучение только ради фана несмотря на внушающую историю их развития.
> Много слышал про xmonad
Говно 15-летней давности. Ну, может, меньше. Написали какой-то там оконный менеджер. В современной венде окнами управлять куда удобнее.
Идея изобретения xmonad была не в том, чтобы создать оконный менеджер, а чтобы доказать, что в Хаскеле возможен нормальный FFI. Ну его там и запилили под этот самый xmonad и он там сработал. Вообще, забей на изобретения Хаскеля 15-летней давности. Хаскель - современный язык, смотри на его современные фишки.
> по сути меняешь конфигурацию, где конфигурационными файлами является исходный код
Ну это тоже уже не новость. По сути, посмотри на SBT, там тоже размыта грань между кодом и конфигурацией. В Лиспе её вообще не было изначально, если это ты про яйца Лиспа спрашивал. Лисп - это код = данные, а Схема - это вообще моноиконичность.
Возможно, парадоксы это такая фишка хаскеля, я немного не понимаю
>Вообще, забей на изобретения Хаскеля 15-летней давности. Хаскель - современный язык, смотри на его современные фишки.
но
>он как-бы никому не нужен, на нём особо не пишут коммерческих проектов.
Про
>В современной венде окнами управлять куда удобнее.
Не согласен глубоко. Тайловые оконные менеджеры самый ок. Очень быстро и удобно зарываешься в терминалы, руки не отрываются от клавиатуры. Vimом и rangerом можно куда быстрее и удобнее оперировать файлами и каталогами, чем аналогичными программами в масдае
Алсо я спрашивал
>В чем меметичность языка?
>Там нет никакой математичности.
Т е хаскель очень мемный ЯП. Ты немного ошибся
Алсо почему хлоуворд на две строчки весит 11.3 мб? ghc 9.0.1 Это тоже МЭМ?
> но
И что? Ты собрался погрузиться в его историю? У Хаскеля нет истории как у успешного языка, его изучать имеет смысл только если ты на него как на современный язык дрочишь, либо если собрался из него что-то спиздить. В любом случае, тебе нужна самая современная версия.
> Алсо почему хлоуворд на две строчки весит 11.3 мб?
Потому что там весь рантайм. Он ещ довольно легкий по сравнению с остальными.
>Очень быстро и удобно зарываешься в терминалы, руки не отрываются от клавиатуры.
Нахуя вы это делаете?
Вот это "Очень быстро"?
У вас что не почасовая оплата?
Да, но ты так и не ответил на вопрос, "слово 'моноиконичность' сам придумал?".
> Ни в одном другом языке не было столько фишек, чтобы можно было писать настолько крутые веб-фреймворки.
Lisp, Prolog. А вообще бекенд не нужен. Сразу говори "бекенд" вместо "веб-фреймворк", чтобы путаницу не создавать.
> Не понял, поясни.
Просто. Не нужен. Бекенд не нужен, чего непонятного? Берешь p2p и делаешь веб-приложение без сервера.
Как и все остальные люди. Гомоиконность.
В РОССИИ ПОЯВИЛАСЬ ВАКАНСИЯ ХАСКЕЛИСТА
https://spb.hh.ru/vacancy/47056578
IT_Selection
От 70 000 до 100 000 руб. на руки
Добрый день!
Мы в поиске Haskell разработчика для нашего партнера (компания занимается разработкой продуктов с использованием computer vision для спортивных обучающих программ)
Локация - удаленно
Задачи:
- Разработка серверной части продукта
- Взаимодействие с командами разработки
Пожелания к опыту:
• Опыт разработки на Haskell или базовое знакомство (если у Вас есть курсы СПбГУ или СПбАУ это плюс)
• Знакомство с Elm
• Опыт функционального программирования
• Знакомство с алгоритмами
Мы предлагаем:
• Все официально по ТК РФ
• Гибкий график
• Большое количество задач
• Слаженную команду
Ждем Ваши отклики!
В РОССИИ ПОЯВИЛАСЬ ВАКАНСИЯ ХАСКЕЛИСТА
https://spb.hh.ru/vacancy/47056578
IT_Selection
От 70 000 до 100 000 руб. на руки
Добрый день!
Мы в поиске Haskell разработчика для нашего партнера (компания занимается разработкой продуктов с использованием computer vision для спортивных обучающих программ)
Локация - удаленно
Задачи:
- Разработка серверной части продукта
- Взаимодействие с командами разработки
Пожелания к опыту:
• Опыт разработки на Haskell или базовое знакомство (если у Вас есть курсы СПбГУ или СПбАУ это плюс)
• Знакомство с Elm
• Опыт функционального программирования
• Знакомство с алгоритмами
Мы предлагаем:
• Все официально по ТК РФ
• Гибкий график
• Большое количество задач
• Слаженную команду
Ждем Ваши отклики!
Ты бы хоть ссылку дал на эту технологию. В любом случае, сейчас 99% веб-приложений с серверами и вряд ли это изменится в обозримом будущем.
Авторы Cardano могут выёбываться сколько угодно, но я вот что скажу. Как только эта штука станет по-настоящему массовой, или им потребуется сделать её по-настоящему массовой, будет внедрён быдлоязык. Вот как ты думаешь, почему весь ML сейчас на Питоне? Типа Питон - дохуя подходящий язык для ML? Вроде нет в нём ничего такого, изначально его вообще для другого создавали.
Но дело в том, что сейчас нужно дохуя датасаентистов. И никто не хочет выискивать каких-то там хаскеллистов или вбухивать дохуя ресурсов в их обучение. Гораздо проще язык, в который уже может каждая кухарка, прикрутить к нему какие-нибудь костыли, и решать актуальные задачи.
Да, криво. Да, не оптимально. И как человек, который в общем-то имел дело с Хаскелем и несколькими другими языками, я могу сказать, что на Хаскеле многое немного приятнее получается. НО когда ты делаешь что-то не в стол, а для реального мира, то аргумент "на Хаскелле - красиво, а на Джаваскрипе - это боль и страдание, как вообще можно на этом убогом дерьмище программировать?" идёт лесом, ты сжимаешь зубы и страдаешь, потому что теперь "оптимальность" - это не то, насколько тебе лично приятно программировать, а то, сможешь ли найти достаточно программистов и сделать свою технологию достаточно популярной.
> Ты бы хоть ссылку дал на эту технологию
WrbRTC. На основе этого низкоуровневого протокола построены WebTorrent, IPFS, libp2p, datjs, и куча других протоколов.
Этим можно было троллить 10 лет назад. Скажу по секрету хотя, какой это нахуй секрет, это в каждом State of Haskell Survey, все хаскеллисты давно трудоустроены и давно работают лидами на Java/C++, в лучшем случае на Scala/Rust.
Да даже 10 лет назад ситуация была аналогичной. Мем про "борщехлёбов" (безработный хаскеллист, который хлебает мамкин борщ) троллит разве что своей абсурдностью. Какой нахуй "безработный хаскеллист"? Где ты таких видел?
Хаскель никогда никогда не был языком ньюфагов. Ньюфаг вообще не поймёт, в чем фишка Хаскеля. Ведь для этого его надо сравнить с другими языками, как минимум.
"Фанбои" Хаскеля - это, как правило, сеньёры и лиды. Которые оттарабанили десяток лет на крестах и джавах, а потом, внезапно, в поисках чего-то нового, забрели в Хаскель, увидели ФП done right и охуели от того, что оказывается так можно было в теории.
И весь их батхёрт не от того, что у них денег или работы нет. Денег-то у них побольше чем у тебя будет, и на рынке они востребованы. А от того, что, на самом деле, так нельзя. Потому что Хаскель никому нахуй не нужен и они вынуждены продолжать программировать на своих Крестах и Джаве.
В этом же причина провала всех стартапов на Хаскелле и объявлений, вроде того, что ты принёс. Ну написали бы они, что им нужен джун на Джаве, з.п. 100 т.р. Уверен, такой бы нашелся. Не такая уж плохая зарплата для джуна. Но проблема в том, что на Хаскелле нет джунов в принципе. Хаскелллисты уже сидят в крупных IT-компаниях и пишут на Джаве за 300к. В чем смысл для них идти в непонятные стартапы на 100к? И в чем смысл для потенциального джуна учить Хаскель и иметь те же 100к, при том, что он и на Дажве их так же поимеет и рынок больше? Джуну ведь вообще пофиг на чем писать, для него все языки примерно одинаковы по личным ощущениям.
Ок, возможно. А в чем сакральный смысл отказа от бэкенда в классическом понимании. Ну размазываем мы web-логику как-то иначе, это как-то программирование облегчает, или снимает какие-то задачи?
Что-то орнул с влажных фантазий тимлида из Google.
Ну я сеньор на Java. Функциональное программирование - параша и говно без задач. В лучшем случае умирающий Erlang/Elixir, но не абсолютно бесполезный хаскель.
>Какой нахуй "безработный хаскеллист"? Где ты таких видел?
Сотни зекачеров и нульчанеров. Ни один из них ни дня не работал.
>"Фанбои" Хаскеля - это, как правило, сеньёры и лиды.
Фанбои Хаскеля - это студенты, которые знакомятся с ним на 1-2 курсе. Успешным разрабам фанбойство чуждо. И тем более некогда заниматься изучением ерунды (будь то Haskell, Oberon, Forth, Prolog и т.д.), которая никак не пригодится в решении профессиональных задач для бизнеса. А вот бездельникам, сидящим на шее родителей, нечем заняться.
Это не просто разумно, это уже реальность. Я в криптовалютах не разбираюсь, но посетил их сайт. Там уже какой-то Plutus. Свой язык, в который можно зайти как с Хаскеля, так и с Джаваскрипта. Т.е. язык для быдла для подстраховки они уже подогнали.
Ну и движок у них сейчас на Хаскелле. Возможно, им была нужна высокая надёжность, высокая скорость разработки, у них было мало ресурсов, поэтому и выбрали высокоэффективный (в плане разработки) язык, на котором небольшая команда хорошо подготовленных программистов смогла что-то замутить.
Но, по мере того как они будут расти, эти микрооптимизации, рассчитанные на оптимальное использование высококлассных программистов, отойдут на второй план. Денег у них станет много, им станет важнее, чтобы программы работали максимально быстро, проблему надёжности они закроют наймом достаточного количества тестеров, а проблему эффективности - наймом достаточного количества обычных программистов.
Вангую, что большая часть движка будет переписана на Си++, основным пользовательским языком станет JavaScript (процентов на 80), процентов на 20 они оставят Plutus и некоторые модули на Хаскеле для R&D.
Тут или проект вытягивает язык, или в конечном счете проект портируют под язык, который тянет. Я не думаю, что криптовалютный стартап сможет сделать Хаскель популярным, не первый раз, когда что-то писали на йоба-технологиях, а потом уже адаптировали на чём-то более земном.
> это как-то программирование облегчает, или снимает какие-то задачи?
Непосредственно программирование не облегчает, зато решает проблемы с расширяемостью, доступностью, нецензурируемостью. Кроме того, имеет место идеологическая составляющая - идея свободного интернета, где информация принадлежит всем; интернет неподконтрольный корпорациям и государству.
> Сотни зекачеров и нульчанеров.
Подгони мне этих зекачеров и нульчанеров. Еще раз повторяю:
Я НЕ ВИДЕЛ НИ ОДНОГО ХАСКЕЛЬ-ДЖУНА.
Я НЕ ВИДЕЛ НИ ОДНОГО ЧЕЛОВЕКА, ДЛЯ КОТОРОГО ХАСКЕЛЬ ЯВЛЯЛСЯ БЫ ПЕРВЫМ ИЛИ ОСНОВНЫМ ЯЗЫКОМ.
Я собеседовал программистов различной квалификации. Лиды, бывает, знают и Хаскель и Джаву. Но такого, чтобы человек знал только Хаскель, но при этом не был бы профессионалом в других языках, я не встречал никогда. Может со мной что-то не так?
> Фанбои Хаскеля - это студенты, которые знакомятся с ним на 1-2 курсе
Подгони мне этих студентов. Может быть я отстал от жизни и теперь каждый первый студент - хаскеллист? А потом какие-то злые дядьки заставляют их переквалифицироваться в джавистов и забыть ФП? Ну, блядь, было бы интересно на них взглянуть. Почему они ко мне идут? Может для найма хаскеллиста нужно реально не более 100К предлагать, а все, кто больше, уже забыли это название? Так у нас и на 100К и на 400К вакансии есть, один хуй, я не вижу твоих воображаемых борщехлёбов.
Ну я тебя понял, ты хочешь под шумок навязать какую-то парадигму, которую ты считаешь правильной. С технической стороны это будет тот же фремворк, просто реализованный как-то иначе.
> С технической стороны это будет тот же фремворк
К сожалению, интернет так не исправишь. Проблема глубже. На уровне устройства DNS, провайдеров, государств. Попытка её решить хотя бы одну из этих проблем в лучшем случае лишь к еще одной оверлейной сети (типа I2P, ZeroNet, Yggdrasil), а в худшем случае - арестом.
No way
Зумер, твои влажные фантазии здесь никому неинтересны.
Получишь диплом, пойдешь устраиваться на работу - тогда поймешь, почему все пишут на жабе, а не на хаскале.
1. Spring
2. Hibernate
3. Zookeeper
4. Kafka
5. Hadoop
6. Elasticsearch
7. Cassandra
Теперь показываешь их аналоги на обосранном хаскеле.
Потому что нищий борщехлеб нажрался бояры и не может выйти из запоя?
Там и не только собеседование тимлидов пригрезится.
На что ты отвечаешь? Я не задавал вопросов. Не проецируй любовь к боярам.
>Как бы Хаскель настолько крут, что на нём можно писать что угодно. Можно писать крутые веб-фреймворки. Ни в одном другом языке не было столько фишек, чтобы можно было писать настолько крутые веб-фреймворки. На Хаскеле можно статически проверять ссылки, оптимизировать рутинг, встраивать DSL-ы не меняя сам язык. Но, как показала практика, народ пишет сайты на убогом PHP и JNode.
>>2130107
>В этом же причина провала всех стартапов на Хаскелле и объявлений, вроде того, что ты принёс. Ну написали бы они, что им нужен джун на Джаве, з.п. 100 т.р. Уверен, такой бы нашелся. Не такая уж плохая зарплата для джуна. Но проблема в том, что на Хаскелле нет джунов в принципе.
Борщехлёбы из зекача пользуются технологией «ленивого программирования», аналогичной lazy evaluation.
При этом программа не пишется, а сразу объявляется написанной. Фактическое формирование кода программы должно происходить при первом непосредственном обращении к ней, но поскольку никто не обращается, код тоже не формируется.
Благодаря этому борщееды экономят много времени, которое могут с пользой использоваться для эффективного троллинга и окучивания новичков.
Тем временем новички
Нахуй тебе %любая_задача% на Хаскеле
Сейчас вот сижу эту кату делаю https://www.codewars.com/kata/scott-encoding не факт что верно конечно, но больше половины сделал, и тут я такое встречаю пока чаще всего.
> Завтипы.
Завтипы это не про Хаскелл, а про Idris и Agda. У Хаскелла (выводимые) ADT обыкновенные.
К тому же динамические типы мощнее.
Лиспер, лиспер, друг, дружочек, товарищ и брат, расскажи, как оно вообще у вас? С чего начинать, с какого диалекта? Что попроще? Где матана поменьше?
А зачем его "исправлять"? Он же и так работает нормально.
>тогда поймешь, почему все пишут на жабе, а не на хаскале
А ты уже понял? Может расскажешь тогда?
Орнул. Во-первых, вряд ли ты лично что-то из этого пилишь. Скорее, используешь в разработке. Теперь дальше. Я не хочу разбирать весь твой говносписок, давай первый пункт возьмём
>1. Spring
Какие именно задачи он решает? Почему для написания программы на Джаве нельзя просто использовать Джаву, а надо подключать xml и метаязыковые конструкции, вроде аннотаций и динамически это всё интерпретировать в рантайме с помощью монструозного фреймворка? Подумай над этим на досуге, сеньёр вшивый.
Система типов + попытка систематизации подходов. С первым, надеюсь, всё понятно, второе - это моё личное наблюдение и мне это сложно формализовать, это скорее моя интуиция от использования языка, но попробую объяснить.
Ты верно написал про Лисп, что там гомоиконность гомоиконность, сейчас набегут иксперты, которые будут рассказывать как правильно переводить термины и развитое метапрограммирование. Это значит что на Лиспе можно сделать что угодно. Т.е. теоретически ты можешь написать на Лиспе аналог хаскеллевского тайпчекера и интерпретировать скобкоговно как типизированную программу. Даже свой reader macros сделать и синтаксис как в Хаскелле. Но именно что можешь. Сам по себе Лисп не предоставляет готового инструмента, ты именно что можешь сделать. И люди делают. Но все делают по-разному. Лиспобиблиотеки, сами диалекты Лиспа - они все очень разные.
и
Есть такое понятие, как низкоуровневые языки и высокоуровневые языки. Типа низкоуровневые - это ближе к железу, а высокоуровневые предоставляют какую-то абстракцию. Так вот, Лисп - очень низкоуровневый. Но не в плане близости к железу, а в плане реализуемой парадигмы. Базовая парадигма Лиспа очень низкоуровневая, там почти ничего нет. И уже на ней ты создаёшь более высокоуровневую парадигму, потом, опираясь на неё, пишешь конкретные библиотеки и фреймворки, потом, с их помощью, создаёшь программы.
Хаскель же, напротив, предлагает тебе вполне конкретные парадигмы. Конкретные наборы абстракций, языковых конструкций и практик, которые, по мнению хаскеллистов, наиболее эффективны для решения определенных задач. И их встраивают либо в сам язык, либо в базовые библиотеки. Например, Хаскель предлагает такие конструкции, как функторы или аппликативы, которые описаны в базовой библиотеке, и все производные библиотеки опираются на эти абстракции. Или Хаскель предлагает такие концепции, как конструкторы типов, или тайпклассы, и они встроены в сам язык.
Это позволяет Хаскелю быть некоторой "копилкой знаний" о том, как правильно программировать. О том, какие подходы и абстракции эффективны, а какие - не очень. Наиболее эффективные внедряются и находят своё отражение в языке и библиотеках. Это, одновременно, позволяет Хаскелю быть испытательным полигоном. Там отрабатываются некоторые практики (есть такое понятие, как "языковые расширения" их там вагон https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/table.html) и их потом с удовольствием пиздят в другие языки. Это так же позволяет специализировать компилятор Хаскеля, чтобы он мог оптимизировать наиболее востребованные абстракции. Например, та же IO-монада в Хаскелле просто на пару порядков эффективнее, чем её порт на Скалу в виде cats-io или ZIO.
Т.е. Хаскель, как и Лисп - исследовательские языки. Но у Хаскеля есть серьёзная замашка на то, чтобы быть не только исследовательским, но и практичным. Ты можешь написать на нём программу с использованием самых передовых подходов, и она, по утверждению хаскеллистов, сможет работать и так, без переписывания компиляторов мейнстрим языков. Т.е. ты можешь что-нибудь изобрести на Хаскелле, и на нём же отправить это в продашн.
Система типов + попытка систематизации подходов. С первым, надеюсь, всё понятно, второе - это моё личное наблюдение и мне это сложно формализовать, это скорее моя интуиция от использования языка, но попробую объяснить.
Ты верно написал про Лисп, что там гомоиконность гомоиконность, сейчас набегут иксперты, которые будут рассказывать как правильно переводить термины и развитое метапрограммирование. Это значит что на Лиспе можно сделать что угодно. Т.е. теоретически ты можешь написать на Лиспе аналог хаскеллевского тайпчекера и интерпретировать скобкоговно как типизированную программу. Даже свой reader macros сделать и синтаксис как в Хаскелле. Но именно что можешь. Сам по себе Лисп не предоставляет готового инструмента, ты именно что можешь сделать. И люди делают. Но все делают по-разному. Лиспобиблиотеки, сами диалекты Лиспа - они все очень разные.
и
Есть такое понятие, как низкоуровневые языки и высокоуровневые языки. Типа низкоуровневые - это ближе к железу, а высокоуровневые предоставляют какую-то абстракцию. Так вот, Лисп - очень низкоуровневый. Но не в плане близости к железу, а в плане реализуемой парадигмы. Базовая парадигма Лиспа очень низкоуровневая, там почти ничего нет. И уже на ней ты создаёшь более высокоуровневую парадигму, потом, опираясь на неё, пишешь конкретные библиотеки и фреймворки, потом, с их помощью, создаёшь программы.
Хаскель же, напротив, предлагает тебе вполне конкретные парадигмы. Конкретные наборы абстракций, языковых конструкций и практик, которые, по мнению хаскеллистов, наиболее эффективны для решения определенных задач. И их встраивают либо в сам язык, либо в базовые библиотеки. Например, Хаскель предлагает такие конструкции, как функторы или аппликативы, которые описаны в базовой библиотеке, и все производные библиотеки опираются на эти абстракции. Или Хаскель предлагает такие концепции, как конструкторы типов, или тайпклассы, и они встроены в сам язык.
Это позволяет Хаскелю быть некоторой "копилкой знаний" о том, как правильно программировать. О том, какие подходы и абстракции эффективны, а какие - не очень. Наиболее эффективные внедряются и находят своё отражение в языке и библиотеках. Это, одновременно, позволяет Хаскелю быть испытательным полигоном. Там отрабатываются некоторые практики (есть такое понятие, как "языковые расширения" их там вагон https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/table.html) и их потом с удовольствием пиздят в другие языки. Это так же позволяет специализировать компилятор Хаскеля, чтобы он мог оптимизировать наиболее востребованные абстракции. Например, та же IO-монада в Хаскелле просто на пару порядков эффективнее, чем её порт на Скалу в виде cats-io или ZIO.
Т.е. Хаскель, как и Лисп - исследовательские языки. Но у Хаскеля есть серьёзная замашка на то, чтобы быть не только исследовательским, но и практичным. Ты можешь написать на нём программу с использованием самых передовых подходов, и она, по утверждению хаскеллистов, сможет работать и так, без переписывания компиляторов мейнстрим языков. Т.е. ты можешь что-нибудь изобрести на Хаскелле, и на нём же отправить это в продашн.
Почему нет, есть. Тот же Depended Haskell. Кроме того, пока никто не знает, как сделать depended types правильно. Та же Агда - это всего лишь один из вариантов реализации со своими заёбами. Не факт, что самый лучший. В Хаскелле есть singletons - это шаг к практической реализации depended types. В новой версии компилятора вообще линейные типы добавили, что тоже неплохо. И, в отличие от Агды и прочих пруверов, на Хаскелле реально писать рабочие программы. Ну я очень сомневаюсь, что ты сможешь на Агде что-то для реального мира накодить. А Хаскель - это как раз тот случай, когда берётся ёба-фича и утверждается, что вы реально сможете её использовать в разработке реальных продуктов, и компилятор устроен так, чтобы она работала быстро и даже тулчейн есть, который не хуже, чем у мейнстримовых языков.
> Лисп - очень низкоуровневый
> у Хаскеля есть серьёзная замашка на то, чтобы быть не только исследовательским, но и практичным
Как ты ловко белое вымазал чёрным. Умеешь, могёшь. Завидую.
>Кроме того, пока никто не знает, как сделать depended types правильно.
Как это никто не знает? Что такое тип? Тип - это предикат, который проверяет, подходит ли некий терм некому условию.
Для того чтобы вести в язык зависимые типы требуется, чтобы у язык были тьюринг-полные макросы. Т.е Lisp и Prolog идеальные площадки для исследований над завтипами.
Я рассматриваю зависимые типы так:
У нас есть исполняемая программа A, и есть для которой есть определения:
- Функции вычисления данных.
- Функции вычисления типов.
Сначала мы вычисляем программу исходя из функций вычисления типов на этапе компиляции. Затем уже в рантайме вычисляем программу используя функции вычисления данных.
Вот накидал систему завтипов в прологе за 10 минут. (Пролог это еще то читерство, но уверен, матёрый лиспер бы тоже смог бы легко подобное накидать).
Первые два пика это тот случай, когда программа типово-некорректная: summ3 требует, чтобы первый аргумент был списком из трёх элементов. Однако ему дан аргумент из четырех элементов. Как видите, ошибка вышла еще на этапе компиляции. Последние два пика - тот случай когда программа корректна.
> DependentHaskell
Так его ведь ещё нет.
Может, ты имел в виду LiquidHaskell? Там есть частный случай зависимых типов - refinement types.
В обычным хаскеле тоже есть частный случай завтипов - типы, зависящие от типов (расширение TypeInType).
P.s. Не забывайте про F*, когда речь о завтипах. Там и refinement, и обычные завтипы.
Тут все умудрились неправильные ответы дать на этот вопрос.
Изначальная фишка хаскеля, ради чего его и создали - это ленивость. И до сих пор это единственный ленивый язык, на котором что-то пишут в прод.
>Изначальная фишка хаскеля, ради чего его и создали - это ленивость
А Miranda тогда зачем создали?
Так она была не опен сорс и платной и в проде не дожила до наших дней
Можно сторить бесконечную иерархию видов, как в Агде. Можно сказать, что вот тут у нас типы, вот виды, а дальше иерархия не идёт. Не вижу проблем, это просто подход к реализации языка.
>>2135736
>Так его ведь ещё нет.
Что логично. Нельзя одновременно ограничивать программированием и повышать его выразительную сложность. Важно ловить баланс.
Да тут вообще никто не против Miranda. Пусть будет много языков и разных. Хаскеллисты никогда не были против других языков, это вообще глупо, учитывая что экспериментальные трансляторы той же Агды пишут на Хаскеле. Нахуй нам быть против других языков, если Хаскель - это как раз тот инструмент, который позволяет создавать другие?
> Хаскеллисты никогда не были против других языков, это вообще глупо, учитывая что экспериментальные трансляторы той же Агды пишут на Хаскеле. Нахуй нам быть против других языков, если Хаскель - это как раз тот инструмент, который позволяет создавать другие?
Куколды никогда не были против других мужей, это вообще глупо, учитывая что экстравагантные ебари твоей же Жены ебут ее на глазах Куколда. Нахуй нам быть против других мужей, если Куколд - это как раз тот хуй, который позволяет впускать другие?
АНАЛогия не аргумент.
Мальчик, тебе сколько лет? Хаскеллистам лет по 40 и они асоциальные уёбки. Средней кошкожене 23 года. Что по твоему мнению должен делать хаскельжених? Ебать 23-х летнюю девушку своим вялым? А если у него не стоит? Я хочу себе кошкожену, я даже нашел себе такую на порносайте, ну она себе вибратор втыкает, и что с того? Она молодая, красивая, а мой хуй страр, пусть вибратор ей будет утехой.
Проигрунькал с тебя.
>В чем прикол Хаскеля как языка?
Haskell — это: типы как объекты, каррированные функции как стрелки, HOFs как экспоненциалы, чистота, ссылочная прозрачность, аппликативность и свободные (при совпадении доменов-кодоменов) композиции, equational theory settings / reasoning как следствие, в терминах ТК, в том числе, начальные алгебры / финальные ко-алгебры как фреймворк для описания индуктивных рекурсивных данных (как выход - результаты, значения) и ко-индуктивных ко-рекурсивных потоков данных (как вход); функторы, монады, Kleisli категории - многие индуктивные [возможно] рекурсивные типы данных которые функторы (начиная с Identity, Maybe и List), также, обычные суммы, произведения и степени, то есть кортежи/записи, объединения/варианты и функции - writer, error и reader/environment, для функций более специального вида - prompt, parser, state и cont, par/conc/async как cont для fork/join/io/done языка; функторы, ко-монады, coKleisli категории - ко-индуктивные ко-рекурсивные типы данных которые функторы (простейшие потоки и деревья, например), те же произведения и степени (суммы?), указатели и изменяемые подструктуры (линзы, как функции в), зипперы; свободные монады вокруг типов данных которые функторы - iteratees (которые сами по себе потоки, то есть финальные коалгебры для соответвующих (строго-позитивных таки) функторов), разные языки (eDSL на ADT) и их интерпретаторы; ко-свободные ко-монады для типов данных которые функторы - ?; (под)категории и стрелки - линзы (категория, тензор, но не вполне стрелка), обычные функции, Kleisli стрелки, coKleisli стрелки, стрелки biKleisli категорий, функции ограниченные типом - списки-в-списки, потоки-в-потоки, деревья-в-деревья, сигналы-в-сигналы и поведения-в-поведения (как оно применяется в FRP) и т.п., автоматы, симуляции, преобразователи, некоторые языки-eDSL-на-ADT, опять же; монадические трансформеры как определённого вида натуральные трансформации для определённого вида функторов над разными монадами - WriterT, ErrorT, ReaderT, StateT, ContT, MaybeT, ListT и т.д., например, ReaderT (ConstEnvironment, MutableScope, Resources) IO - эффекты, injectable read-only / write окружение, список ресурсов пополняемый их захватами по мере выполнения и автоматически освобождаемый в конце; полугруппы, моноиды, сворачиваемые и обходимые типы и т.п. категорные и алгебраические типы и классы как «паттерны» и средства декомпозиции.
>В чем прикол Хаскеля как языка?
Haskell — это: типы как объекты, каррированные функции как стрелки, HOFs как экспоненциалы, чистота, ссылочная прозрачность, аппликативность и свободные (при совпадении доменов-кодоменов) композиции, equational theory settings / reasoning как следствие, в терминах ТК, в том числе, начальные алгебры / финальные ко-алгебры как фреймворк для описания индуктивных рекурсивных данных (как выход - результаты, значения) и ко-индуктивных ко-рекурсивных потоков данных (как вход); функторы, монады, Kleisli категории - многие индуктивные [возможно] рекурсивные типы данных которые функторы (начиная с Identity, Maybe и List), также, обычные суммы, произведения и степени, то есть кортежи/записи, объединения/варианты и функции - writer, error и reader/environment, для функций более специального вида - prompt, parser, state и cont, par/conc/async как cont для fork/join/io/done языка; функторы, ко-монады, coKleisli категории - ко-индуктивные ко-рекурсивные типы данных которые функторы (простейшие потоки и деревья, например), те же произведения и степени (суммы?), указатели и изменяемые подструктуры (линзы, как функции в), зипперы; свободные монады вокруг типов данных которые функторы - iteratees (которые сами по себе потоки, то есть финальные коалгебры для соответвующих (строго-позитивных таки) функторов), разные языки (eDSL на ADT) и их интерпретаторы; ко-свободные ко-монады для типов данных которые функторы - ?; (под)категории и стрелки - линзы (категория, тензор, но не вполне стрелка), обычные функции, Kleisli стрелки, coKleisli стрелки, стрелки biKleisli категорий, функции ограниченные типом - списки-в-списки, потоки-в-потоки, деревья-в-деревья, сигналы-в-сигналы и поведения-в-поведения (как оно применяется в FRP) и т.п., автоматы, симуляции, преобразователи, некоторые языки-eDSL-на-ADT, опять же; монадические трансформеры как определённого вида натуральные трансформации для определённого вида функторов над разными монадами - WriterT, ErrorT, ReaderT, StateT, ContT, MaybeT, ListT и т.д., например, ReaderT (ConstEnvironment, MutableScope, Resources) IO - эффекты, injectable read-only / write окружение, список ресурсов пополняемый их захватами по мере выполнения и автоматически освобождаемый в конце; полугруппы, моноиды, сворачиваемые и обходимые типы и т.п. категорные и алгебраические типы и классы как «паттерны» и средства декомпозиции.
> Я НЕ ВИДЕЛ НИ ОДНОГО ХАСКЕЛЬ-ДЖУНА.
Ну я джун, узнал и дрочил на хаскель еще до первой работы. Говорил всем какой он охуенный, что мутабельность зло и тд. Тащемта, после работы и уника времени на хаскель не осталось, поэтому сейчас ничего по фп нового не узнаю.
Алсо, как минимум один однокурсник фпдрочер и он как-то умудрился на первую работу, на первом курсе пойти в стартап на скале. А я то лох, в галере на шарпах пишу. правда в проекте есть аж 5 строчек на фшарпе, но это тупо шарп с другим синтаксисом, хаскелем и близко не пахнет
И я бы точно пошел джуном за еду в хаскель контору, но увы, таких нет. я не в рашке, та вакансия мне не подходит
Буржуи порой набирают стажеров, недавно видел, как в теслу требовался стажер на хаскеле. Но у спидорашки, думаю, шансов нет в принципе.
Если тебе не принципиально важен именно Хаскель и стартапы, и ты ищешь работу, скинь резюмеху на
У нас Java, Scala и Python. Хаскеля не будет, говорю сразу. Но я уважаю их подходы. Я перенаправляю твою резюмеху в наш отдел кадров.
Буржуи тебя наберут на хаскель, вынесут моск на собеседовании, а по факту посадят писать скрипты для автоматизации тестов на питоне. Обычное дело во всяких фаангах.
>
chernichk`v0in.s.vi ANUSsfSjberbank PUNCTUMrbHRu
Читать не умеешь? Я явно написал, что не из рашки
>скинь резюмеху на
chernichkiG\Fn.s.vi ANUSsberbM0rank PUNCTUMrX'!u
Ололо, понимаю мемы про хачкель. Создаю свои, но не шучу их
Ладно, не душни. Не дочитал, что с того?
>>2159318
Их много кто понимает. В Яндексе тебя поймут, в Райфайзене. Мы тут все - люди и все в своей мере немного угораем по ФП. Кто-то меньше, кто-то больше, кто-то как по мне, совсем уж фанатики, что мне не подходит. Просто выбери компанию под себя.
Следи за вакансиями по plutus, сейчас это дело набирает обороты.
Забугорных вакансий есть, так что можно как консультанту работать.
В linkedin группах по фп/хачкелю скидывают свежие вакансии, иногда в tg @haskell-jobs забрасывают.
Не знаю, где то самое отсутствие вакансий. Мало их, но есть же.
А зачем, собсно?
Всё.
Ну а если серьзено, то в основном бэкенды.
Сейчас стали смарт-контракты на Plutus писать.
Тут описание текущего состояния хачкеля, от комьюнити. Не знаю, насколько это всё достоверно.
https://github.com/Gabriel439/post-rfc/blob/main/sotu.md
> Кого мы приглашаем в команду:
> общительных и позитивных:
> высокомерные гик-снобы и мизантропы в компании, почти наверняка, не уживутся.
Расходимся, им дерзкие кабанчики нужны, а не хикки-борщехлёбы.
Сейчас бы хеккочку, да под пледиком. Борщиком бы накормил и отмонадил, ухх бля
Вы видите копию треда, сохраненную 9 января 2022 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.