А у вас никогда не возникало ощущения, что «вот это» уже надоело? Что хочется чего-то нового? «Вот этим» может быть что угодно: игра, работа, машина. Что-то любое, что повторяется изо дня в день. А в программировании? Под катом вы найдете историю об усталости от C# и выборе более интересного подхода.



Передаю слово автору.


В последнее время я немного устал от C#, бесконечные строчки однотипного кода перестают со временем греть душу. В такие моменты иногда хочется заняться чем-то для души. В моем случае это Linux и F#.


По большей части для меня важно, чтобы я вышел из зоны комфорта. В общем-то я так и сделал, сменил систему и язык.


Организуя свой отдых, я столкнулся с тем, что немного непонятно с чего начать. Давайте же немного разберемся, как дело обстоит с F# на Linux.


Основное:


  • Нужен легковесный редактор с поддержкой синтаксиса
  • Нужна поддержка F# Interactive
  • Нужна среда .NET
  • Нужен отладчик (впрочем, как и всегда)

Искушенные хаброжители уже смекнули, что "легковесный редактор" + Microsoft = Visual Studio Code. Надеюсь, она у вас уже стоит :)


Приступим к делу


Итак, с выбором редактора разобрались, теперь со всем остальным по порядку:


  • Вам необходимо поставить пакет mono и fsharp, для большинства Linux систем инструкцию вы найдете здесь. Хоть в инструкции нет Arch Linux (и основанных на нем дистрибутивов), в стандартном репозитории pacman'a эти пакеты, впрочем, присутствуют, да и в инструкции показано как собрать из исходников, так что проблем возникнуть не должно.

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


  • Также поставим .NET Core 2.0.0 (Runtime + SDK), опять же, для большинства систем вы найдете инструкцию здесь. Для Arch Linux проще всего будет поставить пакеты dotnet и dotnet-sdk-2.0 из AUR. Если что, то вот github После этого, перейдем непосредственно уже к подготовке VS Code к нашей работе.

Поставим расширения для поддержки синтаксиса F#, сборки и управлением пакетами Nuget.



Для полноты можно поставить Nuget manager совместимый с .Net Core.



Поставим расширение для отладки (Да, все правильно, написано C#).



После этого клоним вот этот реп, и далее по инструкции делаем:


dotnet restore && code .

Теперь перезагружаем VS Code и ждем пока расширение "отладчика" докачает свои пакеты и нормально развернется.


На самом деле, сейчас уже почти все готово, осталось только протестировать.


  • Создаем где-нибудь папку, запускаем там консоль. Далее выполняем:

dotnet new console -lang F#
dotnet run

Получаем заветные Hello World from F#!


  • Открываем VS Code в этой папке code .
  • Идем в Program.fs и выделяем кусочек кода и жмем Alt+Enter:


запустится долгожданный F# Interactive.



Его также можно использовать для более полезных целей:



Далее посмотрим сборку и отладку.


  • Для настройки директивы сборки нажимаем Ctrl+Shift+B и выбираем .Net Core.


Автоматически сконфигурированный файл нам менять не нужно.


  • После этого снова нажимаем Ctrl+Shift+B и видим, что сборка происходит успешно:


  • После этого F5, выбираем также .Net Core и дальше просто меняем путь до программы.


  • Все, после этого можно поставить точку останова (F9) на нашей единственной строчке и проверить отладчик:


Итак, ваша машина настроена и готова к новым свершениям на замечательном функциональном языке. Приятным бонусом будет то, что ваши наработки можно будет встроить в C# проект (посредством подключения .dll).


Ну мало ли кто не знал)


Об авторе



Максимилиан Спиридонов — разработчик C#, студент МАИ, Microsoft Student Partner. В профессиональную разработку на .NET пришёл ещё в школе. Более 2,5 лет работает с реальными проектами на WPF(MVVM)+C#, MySQL, более 5,5 лет разрабатывал на C#. Основная сфера интересов сейчас — это мобильная разработка на Xamarin. Также, по воле случая в сфере интересов оказались С/С++ и Linux.


Предыдущая статья Максимилиана о С/С++ на Linux в Visual Studio Code.

Также приглашаем вас в чат по F# в Telegram.

Комментарии (38)


  1. alexyr
    11.12.2017 14:19
    +1

    А что известного разрабатывают на F#? Какая область применения вообще?


    1. Szer
      11.12.2017 14:37

      Jet.com например бекенд весь на F#. Объяснение почему


      От себя:
      F# умеет всё что и C# (ООП, наследование, интерфейсы, netcore 2.0 вот это вот всё) + много сверху (Discriminated Unions, partial application, type inference везде где можно, кастомные операторы и пр).
      Для создания бекенда прям самое оно. Система типов круче, ошибиться сложнее.
      Фронты писать в функциональном стиле тоже можно, попытки видел, мне лично не нравится.


      Есть просто отдельные крутые нугеты:
      Logary, Hopac


      1. Sirikid
        11.12.2017 16:38

        type inference везде где можно

        А вот это немного неправда


        кастомные операторы

        С фиксированным приоритетом, зависящем от первого символа afaik


        1. Szer
          11.12.2017 17:06
          +1

          А вот это немного неправда

          Почему же? Где можно, там выводит) Где не получается — надо ручками писать, да.


          С фиксированным приоритетом, зависящем от первого символа afaik

          Это намного лучше чем их полное отсутствие (дада, C#, я о тебе).
          Вполне хватает на любые нужды:
          >>=
          >?>
          >>=.
          |>
          ||>
          !>
          ?>
          и пр.
          Подробнее можно здесь посмотреть как сделать постфиксные, префиксные и инфиксные операторы — http://www.readcopyupdate.com/blog/2014/09/10/custom-ops-associativity-precedence.html


        1. kalininmr
          12.12.2017 07:52

          ну это уже неплохо.


      1. vsapronov
        12.12.2017 02:07

        От себя и как бывший сотрудник Jet.com…

        В компаниях, в которых есть потребность в быстром росте числа программистов все задаются вопросом: как нанять много программистов за короткое время и не потерять в качестве программистов. Как я понял в начале Jet было принято решение, что повышать качество начальной выборки они будут тем, что привлекать функциональных программистов, исходя из предположения, что статистически программисты глубоко интересующиеся функциональным программированием (и F# в частности) лучшего качества, чем все остальные. Подчеркну — статистически. Потом они довольно быстро исчерпали множество таких программистов и от такой экзотической фильтрации пришлось отказаться и начали нанимать всех подряд, кто просто «готов учить F#».

        Кроме плюшек, которые вы уже перечислили (discriminated unions, partial application, type inference, кастомные операторы и пр; система типов круче) есть еще очень важные immutability by default, bindings (async) и null safety (как очень важная разновидность крутой системы типов).

        Однако косяков в F# хватает тоже. Вобщем, кажется, что Microsoft подзабил на F# в последнее время. Кроме того, приходится писать базовые библиотеки, такие как клиентская библиотека для Apache Kafka или как моя FSharp.Json — в то время как какие-нибудь Java-девелоперы наслаждаются клиентом Kafka и Jackson и тратят время на решение бизнесс-задач, а не создание базовой инфраструктуры…


        1. Szer
          12.12.2017 09:11

          Не, не подзабил, т.к. F# всегда был у Microsoft языком второго сорта) Их продукт — C#, а F# делается командой Don Syme на гитхабе.


          Поддержку .NET Core 2 в Visual Studio только-только завезли. Через год может быть паблиш F# проектов в Azure припилят =)


          По поводу инфраструктуры только частично соглашусь. Для большинства библиотек хватает вот этих функций


          let curry f a b = f (a, b)
          let curry3 f a b c = f (a, b, с)
          
          let uncurry f (a, b) = f a b
          let uncurry3 f (a, b, c) = f a b c

          чтобы свободно пользоваться преимуществами F#
          На крайний случай можно небольшую обвязку сочинить поверх библиотеки с функциональным фасадом.


          Кстати Newtonsoft.Json умеет работать с F# из коробки (списки, массивы, DU) кроме option. Достаточно добавить один кастомный Option Converter чтобы вообще всё заработало.


          По поводу Jet.com любопытно. У них не так давно была волна агрессивного рекрутинга, где они предлагали "(high 5 to low 6 figures / year)", релокейт, но надо физически находиться в USA на момент обсуждения.
          Если не секрет почему ушли из Jet.com?


          1. vsapronov
            12.12.2017 17:19

            Нет, Newtonsoft не катит. Мы его пробовали очень долго и упорно. Вы говорите: «достаточно добавить option converter». Дело в том, что правильная трактовка option в JSON — может ли поле принимать значение null. Т.е. int option может быть в JSONе null и в таком случае десериализуется в None. А вот int не может быть null — должен быть Exception. Я уверен, что есть еще много других трактовок, но правильная (со всех сторон) именно эта. В Newtonsoft вы этого не добьетесь никак вообще. Кроме того, в Newtonsoft может выдать null и просто для int, вот так вот в рантайме при попытке использования (не сериализации) получить NPE — в F# это безусловное зло. Короче не поддерживает Newtonsoft null-safety. Как его надо поддерживать вот здесь.

            И это я еще про поддержку юнионов даже не начинал…


          1. vsapronov
            12.12.2017 17:28

            Почему я больше не в Jet.com сказать пока не могу. Как-нибудь напишу статью, когда отпустит.


    1. maxspt
      11.12.2017 14:51

      Область применения схожа с С#, т.е. какие-то корп. решения. Вообще как инструмент очень полезен в сферах ML, кластерных вычислений, анализа больших данных, быстрого анализа данных. ± удобство отдельных библиотек, что-то более красиво и быстро можно написать на F#, нежели на С#, и встроить в более большой проект.


      Известного, ну вот например:
      https://www.microsoft.com/en-us/security-risk-detection/


  1. lassana
    11.12.2017 14:51

    Отчего же не MonoDevelop?


    1. kekekeks
      11.12.2017 17:39
      +2

      MonoDevelop не умеет отлаживать .NET Core по лицензионным соображениям. И не научится. По ним же. Такой вот открытый опенсорсный дотнет-стек от майкрософта.


      1. lumini
        11.12.2017 20:23
        +1

        А почему Rider может? Там какие-то нюансы?


        1. kekekeks
          12.12.2017 01:53

          Райдеровцы первоначально пытались использовать clrdbg (он же vsdbg), но наткнулись на лицензионные препятствия. Софтинка сия выдаёт на старте следующее:


          You may only use the Microsoft .NET Core Debugger (vsdbg) with Visual Studio Code, Visual Studio or Visual Studio for Mac software to help you develop and test your applications.

          В итоге отладки для .NET Core полгода у них не было, так как пришлось делать свою собственную обвязку вокруг libdbgshim.so, которая из Mono работает с COM-интерфейсами coreclr.


          В MonoDevelop же такую обвязку завозить никто не собирается — это теперь просто базовая платформа для VSforMac и Unity, а не самостоятельная полноценная среда разработки.


  1. Sirikid
    11.12.2017 16:43

    В два коротких сниппета доказываю что F# < OCaml. Задача: написать функции для доступа к первому и второму элементам пары.
    OCaml: https://ideone.com/YirJoM
    F#: https://ideone.com/9jPyMF


    1. AnutaU
      11.12.2017 16:49

      Эм…

      let fst (a, b) = a
      let snd (a, b) = b


      1. Sirikid
        11.12.2017 17:25
        +1

        Так неинтересно. В любом случае мой пример нерелевантен из-за разного смысла кода на OCaml и F#.


        1. red75prim
          12.12.2017 12:04

          Можно и так


          let uncurry f (x, y) = f x y
          let k x y = x
          let k' x y = y
          
          let fst<'a,'b> = uncurry k
          let snd<'a,'b> = uncurry k'


      1. red75prim
        11.12.2017 17:26

        Так pointless, извиняюсь, pointfree стиль — это самая мякотка функциональных языков.


         ((+) .) . flip flip 2 . ((+) .) . (*)

        Красота!


        1. AnutaU
          11.12.2017 17:43

          Не то, чтобы я была фп-гуру, так что я могу и ошибаться. Но у меня есть подозрение, что читаемость и здравый смысл не обязательно класть на алтарь pointfree.


  1. papercuter
    11.12.2017 16:57

    Локализованная VSCode порадовала :)


  1. Pinsky
    11.12.2017 17:29

    Что люди не сделают лишь бы на нормальном lisp не писать)


    1. 0xd34df00d
      11.12.2017 17:58

      На нормальном haskell. Зачем ограничиваться императивными языками? :)


      1. Sirikid
        11.12.2017 18:17

        На нормальном Idris, зачем ограничивать себя System F/D? :^)


        1. 0xd34df00d
          11.12.2017 18:25

          Чтобы не писать сигнатуры для вообще всех функций, даже в where-блоках, конечно! Тем более, в ghc 8.8-8.10 завезут полноценные завтипы, при этом постаравшись сохранить вывод типов в большинстве случаев.

          Ну и субъективно ленивость по умолчанию для языков с хаскелеподобным синтаксисом как-то более естественна.


          1. Sirikid
            12.12.2017 19:44

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


            1. 0xd34df00d
              12.12.2017 20:24

              В Idris-то? А можно пример?


              1. Sirikid
                12.12.2017 20:42

                fold : (a -> b -> b) -> b -> List a -> b
                fold op = flip go where
                  go [] = id
                  go (x :: xs) = go xs . op x

                Убедительно?


                1. 0xd34df00d
                  13.12.2017 01:53

                  Вполне.

                  Я тогда перестал понимать, когда сигнатуры не нужны.


                  1. Sirikid
                    13.12.2017 02:13

                    In general, functions defined in a where clause need a type declaration just like any top level function. However, the type declaration for a function f can be omitted if:


                    • f appears in the right hand side of the top level definition
                    • The type of f can be completely determined from its first application


                    1. 0xd34df00d
                      13.12.2017 22:49

                      Интересно, я как-то упустил это. Спасибо!


      1. AlexTheLost
        12.12.2017 13:16
        +1

        Забыли добавить что большую часть времени будет тратится на возню и "срач" какие типы писать. Что затягивает сроки. Но не избавляет от ошибок.
        При изменении бизнес требований, придется переписывать много когда, т.к. все жестко связано типами или вставлять костыли.


        1. 0xd34df00d
          12.12.2017 19:31

          Я не против тратить на это большую часть времени, если интегрально это сэкономит времени на отладку. А по опыту — оно действительно экономит, и сроки не затягивает, причём что на одноразовой парсилке-агрегаторе логов, что на довольно крупномасштабных вещах вроде доморощенных компиляторов. И от ошибок избавляет, на самом деле. Не от всех, конечно, но когда тесты зелёные после любого рефакторинга, и краснеют они только тогда, когда ты играешься с самим алгоритмом — это круто.


          1. AlexTheLost
            12.12.2017 21:40

            Не соглашусь с вашим тезисом, я очень долго работал на статически типизируемых языках со сложной системой типов: Java, Scala.
            По итогу я не нашел преимуществ. Код очень сильно разбухает из-за типов. Изменение в бизнес логике превращаются в переписывание большого куска кода или костыли.
            Разбираться в проектах написанных на языках со сложной системой типов очень трудно, если ты не автор. Нужно сперва изучить всю модель абстракции — за которой скрыта реальная логика работы.
            Если вы утверждаете о каких то домашних проектах то ок, вы в праве писать на чем угодно, но мне слабо верится что в ваш работодатель будет ждать пока вы отрефакторите свою "идеальную" систему типов под новую задачу.
            Скажу ещё так, используя Lisp с которым вы не согласились, а конкретно Clojure, вы напишете ваш проект значительно быстрее и ещё успеете все тестами прокрыть, за время которое вы обдумываете какие типы создать в Haskell, конечно если вам не хватит REPL'a для проверки всего (REPL oriented programming).


            1. 0xd34df00d
              12.12.2017 22:51

              Java

              Опыт системы типов джавы не очень релевантен хаскелю.

              Scala

              Это уже ближе, но это тоже не требует такой же строгости (в смысле чистоты функций и так далее).

              Код очень сильно разбухает из-за типов.

              По сравнению с чем?

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

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

              Но в языках со сложной статической системой типов на моей стороне есть хотя бы типы. Разбираться же в проектах, написанных на питоне/перле/схеме — это как разбираться в вермишели. Модифицировать их — вообще нет, лучше увольте.

              но мне слабо верится что в ваш работодатель будет ждать пока вы отрефакторите свою «идеальную» систему типов под новую задачу

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

              Очень яркий и недавний пример из моего опыта: компилятор для одного наркоманского язычка, когда не было ни формального ТЗ, ничего, только примеры кода на языке и хреновенькая неполная документация для пользователей, которая, по факту, была тоже сборником примеров. Рефакторить хоть фронтенд, хоть кодогенератор мне приходилось не раз и не два, просто потому, что я понимал о задаче что-то новое в процессе её решения, или перед сном мне приходила идея, каким трюком можно ускорить выполнение в N раз — и все эти рефакторинги были быстрые и безболезненные, и после непосредственной реализации алгоритма под вопросом всё просто работало.

              вы напишете ваш проект значительно быстрее и ещё успеете все тестами прокрыть, за время которое вы обдумываете какие типы создать в Haskell, конечно если вам не хватит REPL'a для проверки всего (REPL oriented programming)

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

              В хаскеле тоже есть REPL, кстати.


              1. AlexTheLost
                13.12.2017 02:05

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


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


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


                1. 0xd34df00d
                  13.12.2017 02:10

                  Для меня это звучит аналогично следующему — есть магазин в 100 метрах и я до него дойду за 1 минуту и есть магазин в 1000 метрах до которого вы добежите за 1 минуту, значит добираться до них как минимум однинаково по времени, а может и быстрее если бежать с большей скоростью.

                  Только эта аналогия неверна.

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

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

                  но вот если потратить времени не более чем на продумывание программы на типах, получиться то о чем я говорил — лаконично

                  Я не трачу время на продумывание программы на типах, я просто продумываю программу. Типы данных и сигнатуры функций, где вместо реализаций понатыкано undefined — результат такого продумывания.

                  Вы пишете код не продумывая, что ли?


  1. vasim67
    12.12.2017 15:15

    Друзья, когда Microsoft что-то всерьёз продвигает, то это происходит очень агрессивно (кроме просто рекламы в СМИ: слухи и их опровержения, скандалы в прессе, суды, обещания, разочарования, отставки и назначения, и море других страстей). Ничего похожего с F# и близко нет. Скорее это просто дань моде. Вот и всё.