Порядок программирования персонального кода starline a63

Это может быть странная статья. Несколько лет назад я посмотрел потрясающий фильм “Прибытие”. И он изменил мой взгляд на язык. Чуть позже я впервые столкнулся с F#, и это изменило мой взгляд на языки программирования. В этой статье я расскажу вам об основах некоторых теорий, затронутых в книге Arrival. А затем перейду к роли языка в программировании. Мы сравним и сравним несколько языков и посмотрим, как они влияют на то. Как мы думаем о решении проблем в программной инженерии. Прежде чем мы сделаем более глубокое погружение в язык программирования F#. Я же говорил тебе, что это может быть странная статья.


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

Эта статья будет особенно интересна тем. У кого меньше опыта в функциональном программировании или F#. Идеальный читатель должен иметь опыт работы с C#, Java, JavaScript, TypeScript. Python или подобными языками.

Влияние языка на мышление

Давайте начнем с краткого путешествия в научную фантастику.

Примечание: Этот раздел содержит мягкие спойлеры в первый час сюжета фильма трейлера фильма.

Фильм года-это научно-фантастический драматический фильм с участием Эми Адамс и Джереми Реннера в главных ролях. Это тот фильм, который я люблю, но моя жена спит – фильм с более медленным темпом. В котором группа ученых пытается связаться с инопланетянами. Прибывшими из разных частей света.

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

Инопланетяне с которыми сталкиваются ученые общаются в основном с помощью логограмм содержащих целые предложения по кругу как показано ниже:

Логограммы прибытия | Паттерн татуировки, Татуировки, Фильм прибытия

Есть красивая последовательность примерно 55 минут в фильме. Где они подробно обсуждают чужой язык и его проблемы. И она включает в себя эту цитату от одного из наших главных ученых:

“Если вы погрузитесь в иностранный язык. То вы действительно можете перепрограммировать свой мозг”

Прибытие, 2016

Далее в последовательности обсуждается гипотеза Сапира-Уорфа, и если язык. На котором вы говорите. Может изменить то. Как вы думаете, или. В случае персонажей

Как и следовало ожидать. Вскоре после этого фильм вступает на территорию умопомрачительной научной фантастики. Но это очень хороший фильм. Если вам так хочется.


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

Эта мысль застряла у меня в голове и снова всплыла. Когда я углубился в функциональное программирование.

Влияние языка программирования на мышление

Давайте сделаем краткий обзор нескольких различных языков программирования. Мы рассмотрим некоторые примеры кода из каждого из них и предположим. Какие способы мышления они могут поощрять или препятствовать.

Отказ от ответственности: Я включаю базовую информацию о нескольких языках, на которых я не был широко запрограммирован. Чтобы предложить здоровое разнообразие синтаксиса. Я буду полагаться на некоторые предположения в этом отношении. А также на свой собственный личный опыт работы с языками. В которых мои знания и опыт глубже.

С#

C#-это императивный язык программирования. Созданный для поддержки объектно-ориентированного программирования (ООП) с синтаксисом. Вдохновленным C++ и Java. Как и F# и Visual Basic, C# работает на .NET и может взаимодействовать с другими языками программирования .NET.

Давайте посмотрим на некоторые примеры кода C# из моего игрового проекта давней давности:

Здесь у нас есть класс из игрового контекста, который содержит метод ApplyDamage. Код течет сверху вниз и может вводить или не вводить операторы if для условной логики до того. Как он вернет число. Указывающее нанесенный ущерб.

Этот тип программирования очень типичен для объектно ориентированных языков несмотря на приведенный здесь упрощенный пример и поощряет следующие типы поведения:

  • Мышление о системе в терминах отдельных объектов
  • Фокусировка на операторах if, которые могут или не должны выполняться
  • Добавление свойств, методов и наследования для управления сложностью по мере роста

Здесь я должен отметить, что. Хотя C# был построен как объектно-ориентированный интерпретируемый язык. Он смещается. Чтобы позволить этому языку поддерживать подходы функционального программирования. Такие как F#.

язык JavaScript

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

Вот фрагмент кода JavaScript из другого моего любительского игрового проекта (уже видите паттерн?):

Этот код JavaScript похож на наш пример C# выше в том. Что он представляет собой императивный ряд команд. Которые программа будет выполнять.

Однако есть некоторые заметные отличия от C#.

Наиболее примечательно, что JavaScript слабо типизирован. Это означает. Что его переменные не имеют заранее определенного типа и могут быть повторно использованы для вещей разных типов. Объекты могут иметь новые свойства. Динамически добавляемые или даже удаляемые по мере выполнения программы. Функции также могут быть вызваны с любым количеством параметров, включая меньше или больше. Чем ожидает функция.

В результате программы JavaScript, как правило, чувствуют себя немного более свободными. Чем строго типизированные языки программирования. Эта дополнительная свобода создает некоторые уникальные проблемы. Которые помог облегчить дополнительный синтаксис. Такой как операторы rest и spread ( … ).

МашиНопись

Я не решаюсь включать TypeScript, поскольку TypeScript – это просто другой способ генерации JavaScript, но я думаю. Что стоит кратко обсудить использование кода из – как вы уже догадались-другого моего игрового проекта.

TypeScript — это действительно JavaScript плюс некоторые необязательные объявления типов. Компилятор TypeScript берет код TypeScript и компилирует его до рабочего кода JavaScript. Который затем понятен браузеру.

Из-за этого TypeScript не сильно отличается от JavaScript. Но он добавляет операторы объявления типов.

Оказывается, что объявления типов на самом деле очень важны для того. Как вы думаете о своем коде. Вместо того чтобы задаваться вопросом. Какой тип чего-то является или полагаться на точную документацию. Теперь вы можете увидеть объявление типа рядом с переменной или параметром. Это приятный штрих, однако у него есть и недостатки.

Поскольку TypeScript полагается на программиста для точного определения типов. Он подталкивает вас к типам. Которые легко представить с помощью стандартного синтаксиса. Это, в свою очередь, препятствует передаче функций в качестве параметров.

Если бы вы объявили параметр, который является функцией, которая принимает число и возвращает логическое значение. Этот синтаксис возможен, но все еще труден для запоминания. Записи и чтения. Поэтому вы. Естественно. Склонны делать это реже.

Питон

Python-еще один императивный язык, такой как C# или JavaScript. Но его синтаксис заметно отличается:

Пример кода, взятый из Алгоритмов

Как человек, который занимался только битами программирования на Python. Я не могу слишком много говорить о том. Как Python меняет ваш образ мышления. Кроме как указать. Насколько элегантен синтаксис по сравнению с другими языками.

Это очень минимальный стиль. Требующий отступа над скобками для определения областей действия. Это снижает уровень шума в коде и помогает сосредоточиться на логике.

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

Я также должен указать на сравнение JavaScript и TypeScript с Python: Python позволяет добавить подсказку типа, если вы решите сделать это (и изображено в коде выше). Однако эта функция была добавлена с тех пор, как я в последний раз работал с Python. И в результате я не могу много говорить об этом.

Вперед

Go (также называемый GoLang) является более недавней разработкой и представляет собой другой статически типизированный императивный язык программирования.

Давайте посмотрим на его синтаксис, потому что он немного отличается в нескольких аспектах, кроме того. Где ставятся скобки и скобки:

Пример кода, взятый из Алгоритмов

В Go есть несколько синтаксических тонкостей, с которыми я еще не сталкивался в других языках.

Ключевое слово for гораздо более гибко. Позволяя при необходимости создавать бесконечные циклы. Кроме того, Go использует := в качестве сокращения для declare и assign, что сводит шум к минимуму. Наконец, мы видим быстрый способ замены двух значений с помощью операторов и=.

Я не могу много писать о том. Как Go может повлиять на то. Как мы думаем о написании приложений. Но мне было бы любопытно узнать опыт тех из вас. Кто больше работал с Go.

Моя первоначальная реакция заключается в том. Что он берет много элегантности от Python и применяет ее к синтаксису. Подобному C#. Java и JavaScript. И мне любопытно. Как далеко заходит этот дополнительный “синтаксический сахар” с точки зрения изменения того. Как вы думаете о решении проблем.

Ф#

Все, что я рассматривал до сих пор, было в основном императивным языком программирования. F#, напротив, является функциональным языком программирования. Который опирается на совершенно другие шаблоны кода:

Пример кода, взятый из Алгоритмов

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

Синтаксис F# часто имеет дело с “конвейерными” вещами от функции к функции. Чтобы получить ожидаемый результат.

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

Примечание: F# — не единственный современный функциональный язык программирования, но из моего знакомства с языком F# и того факта , что эта статья технически является частью серии community F# advent 2020, мы обнулим F# на оставшуюся часть статьи.

Другие языки

Если вы хотите подробнее изучить синтаксис многих используемых в настоящее время языков программирования. Я рекомендую вам ознакомиться с Алгоритмами на GitHub для получения набора примеров с открытым исходным кодом. Включая некоторые другие функциональные языки программирования.

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

Как F# Изменил То. Как я думаю о программировании

Отложив в сторону этот обзор языков, давайте глубже погрузимся в язык F# и в то. Как его функции меняют подход к коду.

F# — это не C#

Когда я впервые попытался выучить F#, это был трудный опыт для меня. Это был мой первый функциональный язык программирования, и такие термины, как монады. Частичное применение функций и функции более высокого порядка. Сделали мое путешествие трудным.

Вдобавок к этому, когда я изучал F#, я был сосредоточен на том. “Как мне написать этот код C# в F#?”. Поэтому мои первые попытки в F# пытались создать сильные типы с изменяемым состоянием. Как вы сделали бы в программе C#.

В то время как F# может это сделать, это не то, что F#. F# — это не создание классов с изменяемым состоянием и традиционными членами. А написание функций и объединение этих функций в решения более крупных задач.

В объектно-ориентированных языках мы фокусируемся на инкапсуляции логики в связные объекты и вызове методов на этих объектах в определенной последовательности. Другими словами, классы являются звездами шоу, и их методы помогают вещам работать.

F# promotions фокусирует внимание на отдельных функциях и подталкивает вас к неизменному состоянию и цепочке функций вместе. Функции являются главной достопримечательностью, а типы, которые их поддерживают. Остаются как можно более минимальными (хотя система набора текста F#очень мощная и гибкая).

Мышление в терминах труб

Когда я думаю о приложениях F#, я представляю себе ряд труб. Соединенных друг с другом – каждая из них тщательно разработана. Чтобы иметь точно правильный выход при определенном входе и не иметь никаких других побочных эффектов. Этот тип функции обычно называют чистой функцией.

Отдельные трубы (или функции) малы и узкоспециализированы. Но вместе они делают очень способное применение.

серая коммерческая машина
Фото Кристал Квок на Unsplash

F# как язык очень хорошо связывает вещи вместе благодаря своим специализированным операторам

Просто глядя на присутствие этого единственного изолированного оператора в F#. Множество вещей становится легким в F#. Что было бы сложнее в таком языке, как C#.


Например, посмотрите на следующий код F# :

watermelon |> SliceOpen |> RemoveSeeds

Это берет любой арбуз и передает его в качестве параметра SliceOpen функции. А затем берет результат этого вызова и передает его в RemoveSeeds функцию.

Мы могли бы еще больше упростить это в F#. Используя >>оператор для составления SliceAndRemoveSeeds функции из функций SliceOpen andRemoveSeeds , подобных этому:

let SliceAndRemoveSeeds = SliceOpen >> RemoveSeeds watermelon |> SliceAndRemoveSeeds

Если бы мы хотели сделать то же самое в коде C#. Нам пришлось бы написать следующее:

var slicedWatermelon = SliceOpen(watermelon); var preppedWatermelon = RemoveSeeds(slicedWatermelon);

Следует признать, что мы могли бы немного упростить это, написав:

var preppedWatermelon = RemoveSeeds(SliceOpen(watermelon));

Это действительно работает, но вы можете начать чувствовать, что язык немного борется с вами. И теперь вам нужно научиться читать свой код изнутри. Код F# — это гораздо более последовательный и минимальный синтаксис (хотя к нему нужно немного привыкнуть). Поэтому такой функциональный цепной код становится более естественным в F# vs C#.

Порядок параметров

Поскольку оператор канала всегда передает результат в качестве последнего параметра функции. В которую он передается. Теперь нам нужно обратить внимание на порядок объявления параметров.

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

let AddNumbers x y = x + y let AddTwo = AddNumbers 2 let five = AddTwo 3

Здесь мы определяем AddTwo как функцию. Которая вызывает вызов AddNumbers с первым параметром 2 и вторым параметром unspecified. Далее мы можем вызвать вызов AddTwo со вторым параметром 3, который в конечном итоге сложит 2 и 3 вместе.

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

Порядок кодов

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

Например, на рисунке ниже Gasses.fsфайл может ссылаться на что угодно в Utils.fsиPositions.fs, но не может ссылаться ни на что в GameObjects.fsили ниже.

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

Поскольку функции теперь зависят от порядка. Становится невозможным создавать бесконечные циклы функции A. Вызывающей функцию B. Которая снова вызывает функцию A. И ваши зависимости модуля теперь гораздо проще визуализировать. Компилятор эффективно обеспечивает поток зависимостей только в определенном направлении. Целые инструменты, такие как NDepend, были построены вокруг попыток применить эту концепцию в других кодовых базах.

Интеллектуальный Набор текста

Однако все эти функции, которые я описал выше. Являются просто синтаксическим сахаром для некоторых истинных сильных сторон F#.

F# предлагает несколько действительно интересных механизмов для объявления типов. Возьмите это определение GameObjectType из моего сайд-проекта:

Это похоже на перечисление C# , но предлагает некоторые дополнительные биты логики. Здесь игровым объектом может быть любое количество вещей. Но некоторые вещи имеют дополнительные данные. Связанные с ними. Например, воздушная труба должна отслеживать смесь газов, протекающих через нее. И дверь либо будет слева направо. Либо сверху вниз в 2D-мире и будет либо открыта. Либо закрыта.

В объектно-ориентированном языке мы могли бы использовать наследование и определять подклассы для этих дверей и труб. Но во многих случаях это может быть излишним – особенно когда мы хотим. Чтобы наше внимание было сосредоточено на сжатых. Многоразовых функциях вместо мощных объектов.

Затем мы можем match отключить тип объекта в F#:

Это тот случай. Когда синтаксис F#подтолкнул нас от наследования к использованию интеллектуального ключевого слова match и выражений для обработки различных случаев (при этом _ является подстановочным знаком. Означающим все остальное. Что не соответствует).

В результате наше внимание как разработчиков остается на функциях. А не на создании мощных типов. Это, в свою очередь, заставляет нас сосредоточиться на том. Как наши функции сочетаются другс другом .

Опции над нулями

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

Вот небольшая функция F#. Которая пытается найти плитку 2D-игры в определенном положении внутри другого слоя плитки. Он либо найдет плитку, либо нет, и если это произойдет. То ему нужно будет объединить эту плитку поверх текущей плитки:

F# выбирает обработку нулей в основном с помощью типа опции. Опцион либо будет иметь некоторую ценность, либо его небудет . Option может рассматриваться как универсальный тип в контекстах C# и никогда не будет сам по себе нулевым.

Компилятор F# настаивает на том. Чтобы вы использовали определенные способы получения значения из опции. И явно заставляет вас обрабатывать возможность того. Что опция не является никакой. Это заставляет вас как разработчика явно обрабатывать эти случаи и снижает вероятность того. Что вы случайно забудете обрабатывать нули.

В общем, F# поощряет вас работать с пустыми списками или опциями над явными нулевыми значениями, и компилятор дает вам пощечину вещами. Которые вы. Возможно, забыли. Не все любят сильный и самоуверенный компилятор (поверьте мне. Я знаю это по выступлениям за TypeScript в мире JavaScript). Но компилятор F#ловит ошибки. О которых я даже не подозревал. И это очень ценно для меня как разработчика.

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

Какое отношение F# имеет к

Прежде чем мы закончим. Давайте кратко рассмотрим еще одно художественное произведение и его мысли о языке: классический роман Джорджа Оруэлла

1984 стальной декор

Фото Виктора Форгача на Unsplash

Я читал эту книгу несколько раз в юности. И одним из самых поразительных аспектов ее был язык и то. Как “Министерство истины” в книге пересмотрело речь. Чтобы сделать нежелательные понятия более трудными для представления. Например, такие слова, как “плохо”, были заменены такими вещами. Как “нехорошо”.

Это поразительная картина и пример, независимо от того, были ли вы взволнованы чтением

Для меня ключевая красота языка программирования F# заключается в том. Что F# затрудняет представление недопустимых состояний.

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

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

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

Закрытие

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

Когда вы начинаете новый проект спросите себя об этом:

  • Что делает этот язык легким для меня?
  • Что делает этот язык сложнее?
  • Насколько трудно найти или обучить разработчиков. Которые могут писать и поддерживать этот язык?
  • Сколько тренировок потребуется моей команде, чтобы использовать этот язык?
  • Какую поддержку на этом языке я могу ожидать от официальных и общественных каналов в будущем?
  • Насколько трудно мне использовать этот код для работы с другим существующим кодом. Используемым нашей организацией?
  • Сколько дает мне этот язык и что мне нужно добавить самому?
  • Нравится ли мне тип кода. Который этот язык побуждает меня писать?

Мы должны начать изучать компромиссы выбора языка и то. В какие модели подталкивают нас наши языки. Потому что этот выбор может иметь большее значение. Чем вы понимаете.

Эта статья является частью серии F# Адвент 2020. Проверьте эту серию статей на F# от членов сообщества.