• Функциональное программирование — это не то, что нам рассказывают
    0

    Гарантии примерно те же, как то, что завтра int не устареет, и строчки внезапно принимать не начнет.

  • Microsoft создаёт новый язык программирования, основанный на Rust
    0
    Во-первых, "как C только контролируя безопасность" это и есть оверхед. В glibc например если поставить переменную окружения _MALLOC_CHECK=2 он тоже будет что-то контролировать, но это не продакшн функция а отладочная. Это если про само выделение/освобождение. Если же речь про невыход за границы выделенной памяти то это ещё больше оверхеда (при каждом обращении к массиву сверять индекс с чем-то в памяти, а уж как в таком режиме работать с type-casted указателями я вообще не знаю).

    Почти все проверки раст делает во время компиляции, и рантайм проверки можно тоже выключить. Например, компилятор раста автоматически проверит, что у вас ссылки не алиасятся, и на все указатели/ссылки в прогармме повесит __restrict. Надо ли говорить, что это не замедляет, а ускоряет программу?


    Во-вторых, когда я выше писал про c++ это было не про smart pointers а про RAII. Сам RAII добавляет немного (немного — повторюсь — на современных компиляторах и с качественной реализацией класса) оверхеда, а smart pointers с refcount — это абстракция над RAII которая добавляет ещё оверхеда. Если речь про без refcount то это тоже самое что статический объект. Случай с малым оверхедом это когда функционал smart pointer'а встроен в используемые классы, но не отдельной абстракцией а монолитно.

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


    То есть если хотим максимальной эффективности — возвращаемся в тому что было.

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

  • Функциональное программирование — это не то, что нам рассказывают
    +1

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

  • Функциональное программирование — это не то, что нам рассказывают
    +1

    Нет, перевод будет примерно таким: "По [странному] совпадению, я недавно начал писать на Rust. Я нахожу странным это чувство: люди смотрят на другие языки не потому, что вы не можете что-то сделать в С++, а потому что вы можете [сделать много нехороших вещей]".

  • Функциональное программирование — это не то, что нам рассказывают
    +2

    Открыл один из репозиториев моей текущей работы, посмотрел в бизнес-логику, не нашел там хаков и костылей.


    Наверное, стоит бороться со стереотипом, что работающий код — это исключительно дырявое полотное из заплаток, слепленное на ходу непойми кем?

  • Функциональное программирование — это не то, что нам рассказывают
    0

    Я про такой дизайн и подумал, как, наверное, и любой человек читающий эту ветку. Правда я представлял это как CoffeeOrder или CoffeeTicket.


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

  • Функциональное программирование — это не то, что нам рассказывают
    0

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


    Для полноты картины.


    Но в своих простых случаях я с проблемами взаимозаменяемости не столкнулся.

  • Функциональное программирование — это не то, что нам рассказывают
    0

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


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

  • Функциональное программирование — это не то, что нам рассказывают
    0
    И я уже не только про комбинаторы, но вообще про мелкие «удобные» абстракции.

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

  • Функциональное программирование — это не то, что нам рассказывают
    0

    Ну очень просто ведь: налили кофе, выставили за него счет. Посмотрели, хватает ли средств на списание. Если хватает, списали деньги и отдали кофе, иначе выкинули кофе и клиенту его не отдали.

  • Функциональное программирование — это не то, что нам рассказывают
    0
    Совершенно не интуитивно и не похоже на императивное состояние. К тому же, даёт как неоправданную нагрузку на GC, так и на CPU сначала при генерации функторов, затем с их вложенным вычислением.

    Вы же знаете, что такие заявления без бенчмарков делать не надо.


    А как показывают бенчмарки, тот же хаскель быстрее и Java, и C#. Ну да, помедленнее плюсов, но я и не предлагаю его использовать на тех же задачах. А вот на задачах обычных сервисов и хождений в БД одни плюсы. Разве нет?

  • Функциональное программирование — это не то, что нам рассказывают
    +1

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


    Лично я реализации из стандартной библиотеке доверю больше, чем "инхаус решениям". А вы?

  • Функциональное программирование — это не то, что нам рассказывают
    0

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

  • Функциональное программирование — это не то, что нам рассказывают
    +1
    С тем же успехом я могу написать

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




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

  • Функциональное программирование — это не то, что нам рассказывают
    0

    Ну map это функция которая занимается отображением, к хэшмапе отношения никакого не имеет. В C++ практически такая же функция называется transform. Вот так через неё выражается map:


    template<typename Src, typename Dst, template<class, typename ...> typename Container>
    Container<Dst> map(Container<Src>& container, Dst(*f)(Src)) {
        Container<Dst> result;
        result.reserve(container.size());
        std::transform(container.begin(), container.end(), std::back_inserter(result), f);
        return result;
    }

    Используется вот так:


    vector<int> a = {1, 2, 3};
    auto f = [](int x) -> int { return x*x; };
    vector<double> b = fmap(a, +f);

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


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


    Смущает только строчка int value = a[i];

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

  • Функциональное программирование — это не то, что нам рассказывают
    0

    Мне кажется, это объяснение подходит для того что уже это знает, но они и так знают :)


    А кто не знает — ничего не понял.

  • Функциональное программирование — это не то, что нам рассказывают
    0

    Не собираюсь ничего портить, и обсуждение скатилось куда-то не туда.


    Предлагаю на этом закончить.

  • Функциональное программирование — это не то, что нам рассказывают
    0

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


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

  • Функциональное программирование — это не то, что нам рассказывают
    +1
    Там определение чистой функции а не чистой программы.

    Ну так в нашем случае программа состоит из этой единственной функции. значит все (одна) функции — чистые.


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

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


    Это была иллюстрация, что так можно делать. Но я нигде не говорю, что так делать нужно :)


    Неважно для того, кто вызывает эту функцию, или для программиста который пишет/меняет ее тело?

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

  • Функциональное программирование — это не то, что нам рассказывают
    0
    Вы абсолютно точно уверены, что все без исключения комбинаторы выдадут одинаковый результат во всех популярных языках на всех кейсах? Я — нет.

    Развивайте уверенность, что тут скажешь :)

  • Функциональное программирование — это не то, что нам рассказывают
    0

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

  • Функциональное программирование — это не то, что нам рассказывают
    +1

    Да нет, зачем мне реализация? Хотя не вижу ничего сложного в том, чтобы реализовать на любом языке. Ну вот All например


    bool All<T>(this IEnumerable<T> source, Predicate<T> predicate) {
        foreach (var v in source) {
            if (!predicate(v)) return false;
        }    
        return true;
    }

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




    При этом и посылка неверная. Я сходу не напишу GroupBy эффективно на любом языке. Пользоваться им это мне не мешает.

  • Функциональное программирование — это не то, что нам рассказывают
    +4

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


    Или может не стоило ему так делать?

  • Функциональное программирование — это не то, что нам рассказывают
    0

    Ну для небольшого количества стейтов можно переписать в linq опять же :)


    var final = from x in next
                from y in next2
                select Unit.Instance;
    
    Console.WriteLine(final.Run(100));

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


    public static State<S, A> Sequence<S, A>(this IEnumerable<State<S, A>> states) =>
        states.Aggregate((prev, next) => prev.Bind(_ => next));

    Используем:


    var states = Enumerable.Range(-5, 10).Select(Foo);
    Console.WriteLine(states.Sequence().Run(100)); // 121
  • Функциональное программирование — это не то, что нам рассказывают
    0

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


    Впрочем, хаскеллю 30 лет, думаю это можно списать на возраст. Все же за это время появилось лучшее понимание, что и как делать. Будем надеяться, что дотти и идрис2 будут расти и популяризироваться.

  • Функциональное программирование — это не то, что нам рассказывают
    0

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


    Иногда очень хотелось забить и просто написать SQL, а не думать, какой бы LINQ сгенерировать чтобы нахачить оптимизатор чтобы он выполнил код так, как мне надо, но в целом рассматриваю это скорее плюс.


    А в 90% запросов SQL просто тупо не нужен, EF генерирует тот же код что руками бы был написан.

  • Функциональное программирование — это не то, что нам рассказывают
    0

    Ну в хаскелле он захачен на уровне компилятора, видимо (как-то ведь сам рантайм создает объекты этого типа?), но в тех же котах это обычный тип: https://typelevel.org/cats-effect/datatypes/io.html#pure-values--iopure--iounit


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


    makeIO action result = do
      _ <- action
      pure $ result
    
    main = makeIO (print "Some logs here") 120 >>= print
  • Функциональное программирование — это не то, что нам рассказывают
    0

    Да, вы правы. Тогда использование становится тривиальным:


    var next = Foo(0);
    var next2 = Foo(-1);
    Console.WriteLine(next.Bind(_ => next2).Run(100));

    Правда, в таком случае непонятно как склеивать 2 стейта, там такого эмбиента не получится ведь.

  • Функциональное программирование — это не то, что нам рассказывают
    +4
    1. Пометка возвращаемого результата как IO это не сахар, а просто пометка. У каждой монады есть пара методов, которые интерпретатор выполняет когда до них доходит. В случае IO это какое-то ИО собственно, в случае стейт монады это сохранение стейта, в случае List-монады это применение действия в каждому элементу списка и т.п.
    2. нужно понимать, что как async/await разворачивается в цепочку ContinueWith, так и в do и <- всё разворачивается в такую же цепочку bind, который по смыслу то же самое делают, только называется иначе. Ну и a.ContinueWith(b) это не то же самое что b.ContinueWith(a), поэтому в do-записе порядок важен. В каком запишете в таком цепочка и будет выполнена. Именно тут (и только тут) порядок может влиять на результат, поэтому только в do-блоках нужно быть аккуратнее при перестановке местами строчек. Но т.к. вам язык помогает их найти (вы явно видите блок) — то проблем с этим нет.
    3. Мы спокойно можем поменять результат функции) Она же по сути возвращает структуру IO(Print("Some log here"), 120). Можем подставить её тело в мейн:

    main = do
      result <- IO(Print("Some log here"), 120)
      print result

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


    Какой именно эффект — это не компиляторная магия, она описанна в реализации самого типа IO. Интерпретатор просто запускает на выполнение методы, а там написано, куда какие байты записывать.

  • Функциональное программирование — это не то, что нам рассказывают
    0
    Итого у нас есть чистая функция с нечистым телом. Ни одного вызова чистой функции в программе нет. Считается ли вся программа чистой в данном случае?

    С точки зрения D — является. С точки зрения практических свойств программы — тоже, ведь функция ссылочно прозрачная, а значит что она делает внутри нам всё равно.


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

    В данном случае наша программа состоит из единственной функции, которая является чистой. Что внутри тела, неважно, до тех пор, пока она ссылочно прозрачна.

  • Функциональное программирование — это не то, что нам рассказывают
    +1

    Вы неправильно распарсили, как и я в первый раз) Вам нужен аргумент a чтобы понять насколько инкрементировать текущий стейт. А потом вам нужен сам стейт чтобы узнать его текущее значение.


    Так что там всё правильно написано.

  • Функциональное программирование — это не то, что нам рассказывают
    +4

    То есть вы ожидаете что Get какой-нибудь сущности типа "дай мне текущее время" упадет с HttpException потому что он полез на сервер часы синхронизировать?

  • 3 причины бросить учить английский на уровне Intermediate
    0

    Ну вот в РФ я такого не встречаю. У нас сейчас самый старый проект на 472, который при этом на 80% уже перенесен в микросервисы, которые уже на неткор 3.1 частично переведены, и есть планы до конца года полностью избавиться от ииса и виндовых инсталляций. Ну и уж конечно никакой джанго в дотнете я даже на пушечном выстреле не видел в реальных проектах.


    И есть опасность что копаясь долго в легаси можно сильно отстать по востребованным скилам.

    Вот-вот.


    Субъективно кажется, что у нас культура разработки ощутимо выше. Хотя я ненастоящий икспертт, могу ошибаться.

  • 3 причины бросить учить английский на уровне Intermediate
    0

    Про мой круг и не говорите, у меня у всех знакомых зп в районе 200, +- 50%. Откуда мой круг берет такую статистику — непонятно.


    Что касается ваших данных — очень интересно, надо будет попробовать. Мне казалось, что конртактная работа потому и оплачивается выше, что это не постоянная работа + в неё не включены налоги + проблемы с обычными рабочими вещами вроде отпуска. Если с этим всем всё ок, то надо попробовать.


    Хотя я слышал там легаси махровое. Все же сервисы на вижуалбейсике и net 1.1 в РФ трудно встретить.

  • Функциональное программирование — это не то, что нам рассказывают
    +3

    Окей, я не прав. Не был в курсе насчет escapable деления. Вот так всегда, объясняя узнаешь что-то новое. Объяснять — полезно. Люди, помогайте друг-другу )

  • 3 причины бросить учить английский на уровне Intermediate
    0

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

  • 3 причины бросить учить английский на уровне Intermediate
    0

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

  • Функциональное программирование — это не то, что нам рассказывают
    +1

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


    static State<int, bool> IsZero(State<int, Unit> state)

    К стате, в хаскелле такая нечистая функция есть, правда, не для стейта, а для IO. Называется она unsafePerformIO, и как следует из названия, лучше ей не пользоваться. Против неё есть целая прагма {-# LANGUAGE Safe #-} которая запрещает её использование.


    Значения не должны покидать контекста монады, в котором созданы. Это так же плохо, как выходить из асинхронного контекста функции через task.Result (который тоже является монадой, и именно поэтому так делать не надо). Чревато дедлоками и всеми остальными плохими вещами.


    Поэтому покидать контексты монад — плохо. Для каждой монады последствия такого выхода свои, но всегда — плохие.




    Если кто-то будет это читать, вот тут можно посмотреть итоговый вариант кода после всех исправлений:


    https://gist.github.com/Pzixel/05d6fc18f389149e64995b148147345e

  • Функциональное программирование — это не то, что нам рассказывают
    0

    А вот так можно два стейта разных читать и формировать новый:


    static State<string, Unit> ConcatStates(State<string, Unit> a, State<string, Unit> b) =>
        from __ in a
        from aValue in State.Get<string>()
        from _ in b
        from bValue in State.Get<string>()
        from ___ in State.Set<string>(aValue + bValue)
        select Unit.Instance;
    
    static void Main(string[] args)
    {
        var a = State.Set("Hello ");
        var b = State.Set("World!");
        Console.WriteLine(ConcatStates(a, b).Run(""));
    }

    В общем, мощная штука)) И как видите, работает абсолютно так же, как итераторы или async/await.


    Правда, сперва непривычно и дико, ведь LINQ по традиции используется только с итераторами. Потом привыкаешь.

  • Функциональное программирование — это не то, что нам рассказывают
    +2

    Потому что я снова тупанул и стейт не читаю, он всегда новый создается (если обратите внимание, переменная state не использовалась). Вот так должно быть:


    static State<int, Unit> Foo(int a, State<int, Unit> state) =>
        from __ in state
        from stateValue in State.Get<int>()
        let increment = a > 0 ? 1 : a == 0 ? 2 : 3
        from _ in State.Set(stateValue + increment)
        select Unit.Instance;

    Я еще начинающий ФПшник, тем более в сишарпе где язык сопротивляется :)


    P.S. Когда уже стабилизируют деприкейт _ как имени переменной… Мешает очень.