Что означает синтаксис "просто" в Haskell?
я прочесал интернет для фактического объяснения того, что делает это ключевое слово. Каждый учебник Haskell, который я посмотрел, просто начинает использовать его случайным образом и никогда не объясняет, что он делает (и я смотрел на многих).
вот основной кусок кода из Реальный Мир Хаскелл использует Just
. Я понимаю, что код делает, но я не понимаю, что цель или функция Just
есть.
lend amount balance = let reserve = 100
newBalance = balance - amount
in if balance < reserve
then Nothing
else Just newBalance
из того, что я наблюдал, это связанные с Maybe
печатать, но это все, что мне удалось узнать.
хорошее объяснение чего Just
значит будет очень ценится.
5 ответов:
на самом деле это просто обычный конструктор типа, который определяется в прелюдия, которая является стандартной библиотекой, которая автоматически импортируется в каждый модуль.
что может быть, конструктивно
определение выглядит примерно так:
data Maybe a = Just a | Nothing
это объявление определяет тип,
Maybe a
, который параметризуется переменной типаa
, что просто означает, что вы можете использовать его с любым типом вместоa
.Строительство и разрушение
тип имеет два конструктора,
Just a
иNothing
. Если тип имеет несколько конструкторов, это означает, что значение типа должно быть построено только с одним из возможных конструкторов. Для этого типа значение было либо построено черезJust
илиNothing
, нет никаких других (без ошибок) возможностей.С
Nothing
не имеет типа параметра, когда он используется в качестве конструктора он называет a постоянное значение, которое является членом типаMaybe a
для всех типовa
. Но этоJust
конструктор имеет параметр типа, что означает, что при использовании в качестве конструктора он действует как функция от типаa
доMaybe a
, т. е. он имеет видa -> Maybe a
Итак, конструкторы типа строят значение этого типа; другая сторона вещей-это когда вы хотели бы использовать это значение, и именно там сопоставление шаблонов вступает в игру. В отличие от функций, конструкторы могут быть используется в выражениях привязки шаблонов, и это способ, которым вы можете сделать case analysis значений, принадлежащих типам с несколькими конструкторами.
чтобы использовать
Maybe a
значение в соответствии с шаблоном, вам нужно предоставить шаблон для каждого конструктора, например:case maybeVal of Nothing -> "There is nothing!" Just val -> "There is a value, and it is " ++ (show val)
в этом случае выражение, первый шаблон будет соответствовать, если значение было
Nothing
, и второй будет соответствовать, если значение было построено сJust
. Если второй соответствует, он также связывает имяval
в параметр, который был передан вJust
конструктор, когда было построено значение, с которым вы сопоставляете.Что Может Означать
может быть, вы уже были знакомы с тем, как это работает; на самом деле нет никакой магии
Maybe
значения, это просто нормальный алгебраический тип данных Хаскелла (ADT). Но он используется совсем немного, потому что он эффективно "поднимает" или расширяет тип, такой какInteger
из вашего примера, в новый контекст, в котором он имеет дополнительное значение (Nothing
) это означает отсутствие ценности! Затем система типов требует, чтобы вы проверили это дополнительное значение, прежде чем оно позволит вам получитьInteger
это может быть там. Это предотвращает значительное количество ошибок.многие языки сегодня обрабатывают такое значение "без значения" с помощью нулевых ссылок. Тони хор, выдающийся компьютерный ученый (он изобрел Quicksort и является лауреатом премии Тьюринга), владеет до этого как его "ошибка на миллиард долларов". Тип "может быть" - это не единственный способ исправить это, но он оказался эффективным способом сделать это.
может быть, как функтор
идея преобразования одного типа в другой такой, что операции над старым типом могут и преобразование для работы над новым типом-это концепция, лежащая в основе класса типа Haskell под названием
Functor
, которыйMaybe a
имеет полезный экземпляр.
Functor
обеспечивает метод называетсяfmap
, который отображает функции, которые варьируются по значениям из базового типа (например,Integer
) к функциям, которые варьируются по значениям от поднятого типа (например,Maybe Integer
). Функция, преобразованная с помощьюfmap
для работы наMaybe
значение работает следующим образом:case maybeVal of Nothing -> Nothing -- there is nothing, so just return Nothing Just val -> Just (f val) -- there is a value, so apply the function to it
так что если у вас есть
Maybe Integer
стоимостьюm_x
иInt -> Int
функцииf
, вы можете сделатьfmap f m_x
чтобы применить функциюf
непосредственноMaybe Integer
не беспокоясь, если это на самом деле есть значение или нет. На самом деле, вы могли бы применить целую цепочку поднятыхInteger -> Integer
функцииMaybe Integer
значения и только должны беспокоиться о явной проверкеNothing
один раз, когда вы закончите.может быть, как монада
я не знаю, насколько вы знакомы с понятием
Monad
пока нет, но вы хотя бы использовалиIO a
раньше, и подпись типаIO a
выглядит удивительно похожим наMaybe a
. ХотяIO
в том, что он не подвергайте его конструкторы для вас и, таким образом, могут быть "запущены" только системой времени выполнения Haskell, это все ещеFunctor
кроме того,Monad
. На самом деле, есть важный смысл, в которомMonad
- это просто особый видFunctor
С некоторыми дополнительными функциями, но это не место для разговора об этом.во всяком случае, монады любят
IO
сопоставьте типы с новыми типами, которые представляют "вычисления, которые приводят к значениям", и вы можете поднять функции вMonad
типы через оченьfmap
-как функция называетсяliftM
что превращает регулярную функцию в " вычисление, которое приводит к значению, полученному при оценке функции."вы, наверное, догадались (если вы читали это далеко), что
Maybe
тожеMonad
. Он представляет собой "вычисления, которые могут не возвращать значение". Так же, как и сfmap
например, это позволяет выполнять целую кучу вычислений без явной проверки ошибок после каждого шага. И в самом деле так элементMonad
экземпляр построен, вычисление наMaybe
значения остановка как только aNothing
встречается, так что это похоже на немедленное прерывание или бесполезное возвращение в середине вычисления.Вы Могли Бы Написать, Может Быть,
как я уже говорил, нет ничего присущего
Maybe
тип, который выпекается в синтаксисе языка или системы. Если Haskell не предоставил его по умолчанию, вы можете предоставить все его функциональность себя! На самом деле, вы можете написать его снова самостоятельно, с разными именами, и получить ту же функциональность.надеюсь, вы понимаете
Maybe
тип и его конструкторы сейчас, но если есть еще что-то непонятное, дайте мне знать!
большинство текущих ответов являются сугубо техническими объяснениями того, как
Just
и друзья работают; я подумал, что могу попробовать объяснить, для чего это нужно.многие языки имеют значение, как
null
что можно использовать вместо реального значения, по крайней мере для некоторых типов. это сделало много людей очень сердитыми и широко рассматривается как плохой шаг. тем не менее, иногда полезно иметь такое значение, какnull
, чтобы указать на отсутствие вещь.Haskell решает эту проблему, заставляя вас явно отмечать места, где вы можете иметь
Nothing
(его версияnull
). В принципе, если ваша функция обычно возвращает типFoo
, он вместо этого должен возвращать типMaybe Foo
. Если вы хотите указать, что нет никакого значения, вернитеNothing
. Если вы хотите вернуть значениеbar
, следует вернутьJust bar
.так что в принципе, если вы не можете иметь
Nothing
, вам не нужноJust
. Если вы может бытьNothing
, выJust
.в этом нет ничего волшебного
Maybe
; он построен на системе типа Haskell. Это означает, что вы можете использовать все обычные Хаскелл шаблоны трюки с ним.
дали типа
t
, стоимостьюJust t
существующее значение типаt
, гдеNothing
представляет собой неспособность достичь значения или случай, когда наличие значения было бы бессмысленным.в вашем примере наличие отрицательного баланса не имеет смысла, и поэтому, если такая вещь произойдет, она будет заменена
Nothing
.для другого примера, это может быть использовано в делении, определяя функцию деления, которая принимает
a
иb
, и возвращаетJust a/b
еслиb
не равно нулю, аNothing
в противном случае. Он часто используется таким образом, как удобная альтернатива исключениям или, как ваш предыдущий пример, для замены значений, которые не имеют смысла.
общая функция a - >b может найти значение типа b для каждого возможного значения типа a.
в Haskell не все функции полной. В данном конкретном случае функция
lend
не является полным - он не определен для случая, когда баланс меньше резерва (хотя, на мой вкус, было бы более разумно не допускать, чтобы newBalance был меньше резерва - как есть, вы можете заимствовать 101 из баланса 100).другие проекты, которые имеют дело с общей функции:
- исключение броска при проверке входного значения не соответствует диапазону
- возвращает специальное значение (примитивный тип): favourite choice-это отрицательное значение для целочисленных функций, которые должны возвращать натуральные числа (например, String.indexOf-когда подстрока не найдена, возвращаемый индекс обычно считается отрицательным)
- возвращает специальное значение (указатель): NULL или некоторые такие
- молча вернуться без делать что угодно: например,
lend
может быть написано, чтобы вернуть старый баланс, если условие для кредитования не выполняется- возвращает специальное значение: Nothing (или Left wrapping some error description object)
это необходимые ограничения дизайна в языках, которые не могут обеспечить полноту функций (например, Agda может, но это приводит к другим осложнениям, таким как становление Turing-неполным).
проблема с возвратом специального значения или исключение метания заключается в том, что вызывающий объект легко опустить обработку такой возможности по ошибке.
проблема с молчаливым отбрасыванием сбоя также очевидна-вы ограничиваете то, что вызывающий может сделать с функцией. Например, если
lend
возвращенный старый баланс, вызывающий абонент не имеет возможности узнать, изменился ли баланс. Это может быть или не быть проблемой, в зависимости от намеченной цели.решение Хаскелла заставляет вызывающего частичную функцию дело с типом, как
Maybe a
илиEither error a
из-за возвращаемого типа функции.таким образом
lend
Как определено, это функция, которая не всегда вычисляет новый баланс - для некоторых обстоятельств новый баланс не определен. Мы сигнализируем об этом обстоятельстве вызывающему абоненту либо возвращая специальное значение Nothing, либо обертывая новый баланс в Just. Теперь у абонента есть свобода выбора: либо обрабатывать отказ в кредитовании особым образом, либо игнорировать и использовать старый баланс - например,maybe oldBalance id $ lend amount oldBalance
.