А у вас никогда не возникало ощущения, что «вот это» уже надоело? Что хочется чего-то нового? «Вот этим» может быть что угодно: игра, работа, машина. Что-то любое, что повторяется изо дня в день. А в программировании? Под катом вы найдете историю об усталости от 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)
lassana
11.12.2017 14:51Отчего же не MonoDevelop?
kekekeks
11.12.2017 17:39+2MonoDevelop не умеет отлаживать .NET Core по лицензионным соображениям. И не научится. По ним же. Такой вот открытый опенсорсный дотнет-стек от майкрософта.
lumini
11.12.2017 20:23+1А почему Rider может? Там какие-то нюансы?
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, а не самостоятельная полноценная среда разработки.
Sirikid
11.12.2017 16:43В два коротких сниппета доказываю что F# < OCaml. Задача: написать функции для доступа к первому и второму элементам пары.
OCaml: https://ideone.com/YirJoM
F#: https://ideone.com/9jPyMFAnutaU
11.12.2017 16:49Эм…
let fst (a, b) = a let snd (a, b) = b
red75prim
11.12.2017 17:26Так pointless, извиняюсь, pointfree стиль — это самая мякотка функциональных языков.
((+) .) . flip flip 2 . ((+) .) . (*)
Красота!
AnutaU
11.12.2017 17:43Не то, чтобы я была фп-гуру, так что я могу и ошибаться. Но у меня есть подозрение, что читаемость и здравый смысл не обязательно класть на алтарь pointfree.
Pinsky
11.12.2017 17:29Что люди не сделают лишь бы на нормальном lisp не писать)
0xd34df00d
11.12.2017 17:58На нормальном haskell. Зачем ограничиваться императивными языками? :)
Sirikid
11.12.2017 18:17На нормальном Idris, зачем ограничивать себя System F/D? :^)
0xd34df00d
11.12.2017 18:25Чтобы не писать сигнатуры для вообще всех функций, даже в where-блоках, конечно! Тем более, в ghc 8.8-8.10 завезут полноценные завтипы, при этом постаравшись сохранить вывод типов в большинстве случаев.
Ну и субъективно ленивость по умолчанию для языков с хаскелеподобным синтаксисом как-то более естественна.Sirikid
12.12.2017 19:44Не для всех функций в where-блоках нужно писать сигнатуры, а для топлевел функций в хаскеле и так почти все их пишут. А ещё можно прямо из "дырки" создать функцию с сигнатурой.
0xd34df00d
12.12.2017 20:24В Idris-то? А можно пример?
Sirikid
12.12.2017 20:42fold : (a -> b -> b) -> b -> List a -> b fold op = flip go where go [] = id go (x :: xs) = go xs . op x
Убедительно?
0xd34df00d
13.12.2017 01:53Вполне.
Я тогда перестал понимать, когда сигнатуры не нужны.Sirikid
13.12.2017 02:13In general, functions defined in a
where
clause need a type declaration just like any top level function. However, the type declaration for a functionf
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
AlexTheLost
12.12.2017 13:16+1Забыли добавить что большую часть времени будет тратится на возню и "срач" какие типы писать. Что затягивает сроки. Но не избавляет от ошибок.
При изменении бизнес требований, придется переписывать много когда, т.к. все жестко связано типами или вставлять костыли.0xd34df00d
12.12.2017 19:31Я не против тратить на это большую часть времени, если интегрально это сэкономит времени на отладку. А по опыту — оно действительно экономит, и сроки не затягивает, причём что на одноразовой парсилке-агрегаторе логов, что на довольно крупномасштабных вещах вроде доморощенных компиляторов. И от ошибок избавляет, на самом деле. Не от всех, конечно, но когда тесты зелёные после любого рефакторинга, и краснеют они только тогда, когда ты играешься с самим алгоритмом — это круто.
AlexTheLost
12.12.2017 21:40Не соглашусь с вашим тезисом, я очень долго работал на статически типизируемых языках со сложной системой типов: Java, Scala.
По итогу я не нашел преимуществ. Код очень сильно разбухает из-за типов. Изменение в бизнес логике превращаются в переписывание большого куска кода или костыли.
Разбираться в проектах написанных на языках со сложной системой типов очень трудно, если ты не автор. Нужно сперва изучить всю модель абстракции — за которой скрыта реальная логика работы.
Если вы утверждаете о каких то домашних проектах то ок, вы в праве писать на чем угодно, но мне слабо верится что в ваш работодатель будет ждать пока вы отрефакторите свою "идеальную" систему типов под новую задачу.
Скажу ещё так, используя Lisp с которым вы не согласились, а конкретно Clojure, вы напишете ваш проект значительно быстрее и ещё успеете все тестами прокрыть, за время которое вы обдумываете какие типы создать в Haskell, конечно если вам не хватит REPL'a для проверки всего (REPL oriented programming).0xd34df00d
12.12.2017 22:51Java
Опыт системы типов джавы не очень релевантен хаскелю.
Scala
Это уже ближе, но это тоже не требует такой же строгости (в смысле чистоты функций и так далее).
Код очень сильно разбухает из-за типов.
По сравнению с чем?
В случае Haskell — это вопрос топ-левел-аннотаций, да и те вы вполне можете опустить, они скорее полезны для общей читаемости и улучшения ругани тайпчекера.
Разбираться в проектах написанных на языках со сложной системой типов очень трудно, если ты не автор. Нужно сперва изучить всю модель абстракции — за которой скрыта реальная логика работы.
Но в языках со сложной статической системой типов на моей стороне есть хотя бы типы. Разбираться же в проектах, написанных на питоне/перле/схеме — это как разбираться в вермишели. Модифицировать их — вообще нет, лучше увольте.
но мне слабо верится что в ваш работодатель будет ждать пока вы отрефакторите свою «идеальную» систему типов под новую задачу
А не надо ждать. Наоборот, как-то так получается, что я на своих хаскелях задачи решаю быстрее, эффективнее и надёжнее, чем люди это делают на питонах. Про clojure или scheme не скажу, вокруг меня маловато людей, их знающих и их реально использующих.
Очень яркий и недавний пример из моего опыта: компилятор для одного наркоманского язычка, когда не было ни формального ТЗ, ничего, только примеры кода на языке и хреновенькая неполная документация для пользователей, которая, по факту, была тоже сборником примеров. Рефакторить хоть фронтенд, хоть кодогенератор мне приходилось не раз и не два, просто потому, что я понимал о задаче что-то новое в процессе её решения, или перед сном мне приходила идея, каким трюком можно ускорить выполнение в N раз — и все эти рефакторинги были быстрые и безболезненные, и после непосредственной реализации алгоритма под вопросом всё просто работало.
вы напишете ваш проект значительно быстрее и ещё успеете все тестами прокрыть, за время которое вы обдумываете какие типы создать в Haskell, конечно если вам не хватит REPL'a для проверки всего (REPL oriented programming)
Какая-то ложная дихотомия. Типы у вас на самом деле и в самом последнем лиспе есть, просто лишь динамические. Это выгодно на начальном этапе развития программы, но через несколько дней и сот строк кода такой подход начинает серьёзно проигрывать.
В хаскеле тоже есть REPL, кстати.AlexTheLost
13.12.2017 02:05Вы считаете что написать много типов это так же быстро как их не писать. Для меня это звучит аналогично следующему — есть магазин в 100 метрах и я до него дойду за 1 минуту и есть магазин в 1000 метрах до которого вы добежите за 1 минуту, значит добираться до них как минимум однинаково по времени, а может и быстрее если бежать с большей скоростью.
Если бы у меня не было богатого опыта со Scala, на реальных крупных проектах, а не коленочных поделках, были бы сомнения насколько полезно писать программы с большим кол-во пользовательских типов и связей между ними.
Про вермишель на питоне/перле/схеме, тут вы передергиваете имхо, на этих языках можно решить задачу намного лаконичнее — компактно и без потери читаемости.
Конечно если вы на одну чашу весов ставите код на Haskell подобном языке где выстрадана структура типов и приведена к читаемому виду, а на другой написаный на коленке код на перечисленных языка, преимущества не на стороне последних, но вот если потратить времени не более чем на продумывание программы на типах, получиться то о чем я говорил — лаконично.0xd34df00d
13.12.2017 02:10Для меня это звучит аналогично следующему — есть магазин в 100 метрах и я до него дойду за 1 минуту и есть магазин в 1000 метрах до которого вы добежите за 1 минуту, значит добираться до них как минимум однинаково по времени, а может и быстрее если бежать с большей скоростью.
Только эта аналогия неверна.
Если бы у меня не было богатого опыта со Scala, на реальных крупных проектах, а не коленочных поделках, были бы сомнения насколько полезно писать программы с большим кол-во пользовательских типов и связей между ними.
Увы, я недостаточно знаю скалу, а опыта с ней у меня вообще, считайте, и нет. Есть опыт с большими проектами на хаскеле, правда, но про это я уже писал выше, не хочу повторяться.
но вот если потратить времени не более чем на продумывание программы на типах, получиться то о чем я говорил — лаконично
Я не трачу время на продумывание программы на типах, я просто продумываю программу. Типы данных и сигнатуры функций, где вместо реализаций понатыкано undefined — результат такого продумывания.
Вы пишете код не продумывая, что ли?
vasim67
12.12.2017 15:15Друзья, когда Microsoft что-то всерьёз продвигает, то это происходит очень агрессивно (кроме просто рекламы в СМИ: слухи и их опровержения, скандалы в прессе, суды, обещания, разочарования, отставки и назначения, и море других страстей). Ничего похожего с F# и близко нет. Скорее это просто дань моде. Вот и всё.
alexyr
А что известного разрабатывают на F#? Какая область применения вообще?
Szer
Jet.com например бекенд весь на F#. Объяснение почему
От себя:
F# умеет всё что и C# (ООП, наследование, интерфейсы, netcore 2.0 вот это вот всё) + много сверху (Discriminated Unions, partial application, type inference везде где можно, кастомные операторы и пр).
Для создания бекенда прям самое оно. Система типов круче, ошибиться сложнее.
Фронты писать в функциональном стиле тоже можно, попытки видел, мне лично не нравится.
Есть просто отдельные крутые нугеты:
Logary, Hopac
Sirikid
А вот это немного неправда
С фиксированным приоритетом, зависящем от первого символа afaik
Szer
Почему же? Где можно, там выводит) Где не получается — надо ручками писать, да.
Это намного лучше чем их полное отсутствие (дада, C#, я о тебе).
Вполне хватает на любые нужды:
>>=
>?>
>>=.
|>
||>
!>
?>
и пр.
Подробнее можно здесь посмотреть как сделать постфиксные, префиксные и инфиксные операторы — http://www.readcopyupdate.com/blog/2014/09/10/custom-ops-associativity-precedence.html
kalininmr
ну это уже неплохо.
vsapronov
От себя и как бывший сотрудник 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 и тратят время на решение бизнесс-задач, а не создание базовой инфраструктуры…
Szer
Не, не подзабил, т.к. F# всегда был у Microsoft языком второго сорта) Их продукт — C#, а F# делается командой Don Syme на гитхабе.
Поддержку .NET Core 2 в Visual Studio только-только завезли. Через год может быть паблиш F# проектов в Azure припилят =)
По поводу инфраструктуры только частично соглашусь. Для большинства библиотек хватает вот этих функций
чтобы свободно пользоваться преимуществами F#
На крайний случай можно небольшую обвязку сочинить поверх библиотеки с функциональным фасадом.
Кстати Newtonsoft.Json умеет работать с F# из коробки (списки, массивы, DU) кроме option. Достаточно добавить один кастомный Option Converter чтобы вообще всё заработало.
По поводу Jet.com любопытно. У них не так давно была волна агрессивного рекрутинга, где они предлагали "(high 5 to low 6 figures / year)", релокейт, но надо физически находиться в USA на момент обсуждения.
Если не секрет почему ушли из Jet.com?
vsapronov
Нет, Newtonsoft не катит. Мы его пробовали очень долго и упорно. Вы говорите: «достаточно добавить option converter». Дело в том, что правильная трактовка option в JSON — может ли поле принимать значение null. Т.е.
int option
может быть в JSONеnull
и в таком случае десериализуется вNone
. А вотint
не может бытьnull
— должен быть Exception. Я уверен, что есть еще много других трактовок, но правильная (со всех сторон) именно эта. В Newtonsoft вы этого не добьетесь никак вообще. Кроме того, в Newtonsoft может выдать null и просто дляint
, вот так вот в рантайме при попытке использования (не сериализации) получить NPE — в F# это безусловное зло. Короче не поддерживает Newtonsoft null-safety. Как его надо поддерживать вот здесь.И это я еще про поддержку юнионов даже не начинал…
vsapronov
Почему я больше не в Jet.com сказать пока не могу. Как-нибудь напишу статью, когда отпустит.
maxspt
Область применения схожа с С#, т.е. какие-то корп. решения. Вообще как инструмент очень полезен в сферах ML, кластерных вычислений, анализа больших данных, быстрого анализа данных. ± удобство отдельных библиотек, что-то более красиво и быстро можно написать на F#, нежели на С#, и встроить в более большой проект.
Известного, ну вот например:
https://www.microsoft.com/en-us/security-risk-detection/