Основы системы типов Haskell
Мощная статическая система типов Haskell — одна из его отличительных черт. Одним из необходимых условий для изучения Haskell является понимание этой системы. Он значительно отличается от динамической типизации, используемой в таких языках, как Python, Javascript и Ruby. В некоторых аспектах он даже отличается от других статически типизированных языков, таких как Java, Typescript и C++.
Чтобы понять, почему система типов так важна, мы должны сначала изучить преимущества и недостатки статической типизации. Тот факт, что многие ошибки обнаруживаются во время компиляции, а не во время выполнения, является значительным преимуществом статической типизации. Вы можете поставлять код, который отлично работает на языке с динамической типизацией. Но затем, в производственной среде, пользователь сталкивается с пограничной ситуацией, например, забыв преобразовать что-то в число, и тогда ваше приложение аварийно завершает работу.
Статическая типизация в первую очередь предотвращает компиляцию вашего кода. Это также означает, что неисправности с большей вероятностью будут обнаружены сразу после их возникновения. Ошибка сборки будет вызвана в источнике объекта, а не позже в цепочке вызовов, где он фактически используется. В результате статическая типизация требует гораздо меньше модульного тестирования с точки зрения согласования типов методов. Это не оправдывает полного отсутствия тестирования, но облегчает нагрузку.
Итак, каковы недостатки статически типизированного языка программирования? Во-первых, развитие может быть медленнее. В динамически типизированном языке, как правило, гораздо проще собрать решение. Допустим, вы неожиданно обнаружили, что полезно выполнять транзакцию базы данных в середине чистого кода. С Haskell это действительно сложно, но гораздо проще с Javascript или Python.
Помнить фундаментальную разницу между функциональным и императивным программированием — это первый шаг к полному пониманию системы типов Haskell. Мы даем программе набор команд для запуска в императивном программировании. Наш код в функциональном программировании состоит из выражений, которые необходимо вычислить. Каждое выражение имеет тип в системе типов Haskell.
Кратко, функциональное программирование не изменяет состояние, в то время как императивное программирование изменяет состояние. Есть еще много всего, о чем я могу рассказать в другой статье.
Посмотрите на следующий пример кода.
func baseAmt str = replicate rptAmt newStr where rptAmt = if baseAmt > 5 then baseAmt else baseAmt + 2 newStr = “Hello “ ++ str
Обратите внимание, что в этой функции мы не присваиваем нашим выражениям никаких типов, как в случае с переменными Java или C++. Без нашего уведомления компилятор уже понимает, что «baseAmt» — это целое число, а «str» — это строка. Кроме того, компилятор уже знал бы, что результирующий тип представляет собой список строк, если бы мы использовали результат этого метода в другом месте нашего кода.
Мы также можем наблюдать некоторое влияние системы типов на синтаксис кода. Поскольку каждое выражение имеет тип, все операторы if должны содержать ветвь else того же типа, что и результат обеих ветвей. В противном случае компилятор понятия не имел бы, в чем проблема, в данном случае зная тип «rptAmt».
Хотя обычно мы можем избегать использования сигнатур типов, тем не менее обычной практикой является предоставление сигнатуры для функций и объектов верхнего уровня. Это связано с тем, что просмотр типов соответствующих функций — лучший способ рассуждать о программе на Haskell. Вот как мы напишем приведенный выше код:
func :: Int -> String -> [String] func baseAmt str = repeat rptAmt newStr where rptAmt = if baseAmt > 5 then baseAmt else baseAmt + 2 newStr = “Hello “ ++ str
На самом деле, вполне разумно указывать типы каждой функции, которая вам потребуется, перед реализацией какой-либо из них в приложении Haskell. Это называется Type Driven Development (TDD).
Функции, как целые числа и строки, являются выражениями в Haskell. В результате все они имеют разные личности. «func» — это функция, которая принимает два входа, Int и String, и возвращает список строк в примере. Мы можем применить функцию, передав ей аргументы. Применение функции изменяет тип выражения. Например, мы можем использовать два аргумента для полного применения нашей функции, и результирующий тип будет списком строк:
myStrings :: [String] myStrings = func 4 “Hello”
Haskell — это язык со статической типизацией, и каждое выражение имеет тип, включающий функции и операторы «если».
Спасибо за чтение
И, если вы не являетесь участником Medium и хотите получить неограниченный доступ к платформе, рассмотрите возможность использования моей реферальной ссылки прямо здесь для регистрации. Это 5 долларов в месяц, и вы получаете неограниченный доступ к моим статьям и многим другим, подобным моим. Спасибо.
Если вы хотите подписаться на мою рассылку, нажмите здесь.