Почему «pure» в «Applicative Maybe» определяется как «pure = Just» и игнорирует «Nothing»?

В исходный код GHC.BaseApplicative Maybe определяется как:

instance Applicative Maybe where
    pure = Just
    ...

Мне интересно, почему чистое определение игнорирует Nothing?

Согласно этому определению, я ожидаю, что

pure Nothing должен уменьшиться до Just Nothing, потому что pure = Just и

Prelude> Just Nothing
Just Nothing

а не на самом деле:

Prelude> pure Nothing
Nothing

Почему это волшебство? Что я не так? Спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
227
2

Ответы 2

Он действительно нет игнорирует Nothing, но вам нужно указать для которыйApplicative, что вы запускаете функцию pure, если мы запустим это с -XTypeApplications, мы можем указать тип Applicative, и тогда мы получим:

$ ghci -XTypeApplications
GHCi, version 8.0.2: http://www.haskell.org/ghc/  :? for help
Prelude> pure @Maybe Nothing
Just Nothing

Если вы не укажете тип, интерпретатор будет "по умолчанию" использовать определенный вариант Applicative (в данном случае IO), так что это означает, что он вернет значение, а стандартное поведение интерпретатора - распечатать значение. «завернутый» в оболочку IO.

Причина, по которой Applicative принимает pure = Just, заключается в том, что он должен соответствовать экземпляру Functor. Этот экземпляр функтора определяется как:

instance Functor Maybe where
    fmap f (Just x) = Just (f x)
    fmap _ Nothing = Nothing

Теперь один из законов, который необходимо выполнить:

fmap f x = pure f <*> x

Итак, если мы определим pure _ = Nothing, это будет означать fmap f x = Nothing <*> x, что означает, что мы «потеряли информацию» о f. В результате, вероятно, единственным разумным решением было бы то, что fmap всегда возвращает Nothing, но это не имеет большого смысла в качестве функтора. Кроме того, это нарушит другое ограничение на уровне функтора, которое гласит, что fmap id x всегда должен возвращать x.

pure перегружен. Когда вы просто набираете pure Nothing отдельно, вы не указываете, какую версию pure вызывать. Сам по себе он имеет тип

pure Nothing :: Applicative f => f (Maybe a)

Если вы конкретно скажете, что хотите Maybe (Maybe a), вы получите то, что ожидаете:

ghci> pure Nothing :: Maybe (Maybe a)
Just Nothing

Однако, когда вы вводите pure Nothing в GHCi, он фактически выбирает создание IO (Maybe a). Это потому, что GHCi пытается выполнить запустить любое действие IO, которое он может. Когда он выполняет действие pure Nothing :: IO (Maybe a), вы получаете обратно Nothing. Вы также можете указать подпись типа:

ghci> pure Nothing :: IO (Maybe a)
Nothing

То есть вы никогда не называли версию pure = Justpure. Вы вызвали другую функцию, также названную pure. Вот почему у вас такое интересное поведение.

Другие вопросы по теме