#c #functional-programming #monads #c 17
#c #функциональное программирование #монады #c 17
Вопрос:
В C std::optional
введено 17, я был доволен этим решением, пока не посмотрел на ссылку. Я знаю Optional
/ Maybe
из Scala, Haskell и Java 8, где optional является монадой и следует монадическим законам. Это не относится к реализации C 17. Как я должен использовать std::optional
, без таких функций, как map
и flatMap
/ bind
, в чем преимущество использования std::optional
vs, например, для возврата -1
, или a nullptr
из функции, если не удается вычислить результат? И что более важно для меня, почему он не std::optional
был разработан как монада, есть ли причина?
Комментарии:
1. C — это не Haskell.
2. Что, если -1 уже является допустимым возвращаемым значением?
3. Если вы возвращаете a
int
и возвращаете-1
как сбой, это означает-1
, что cold никогда не будет допустимым выводом для ввода. В большинстве случаев вы не можете этого сделать. Что касается использования, вы должны обратиться к ссылке4. Вы не можете возвращать
nullptr
данные из функции, возвращаемый тип которой равенint
.5. » но необязательный тип явно происходит из функционального программирования «, что может быть источником вашей путаницы.
Ответ №1:
Существует предложение P0798r0 именно с этим и связанная с ним реализация здесь, на Github. Предложение также относится к общему предложению монадического интерфейса и аналогично используемому std::expected . Также доступны их реализации.
Ответ №2:
Как я должен использовать std ::необязательно, без таких функций, как map и flatMap / bind
Maybe
в Haskell его можно использовать без fmap
него, оно представляет значение, которое может быть, а может и не быть. Это также привносит в систему типов различие, поэтому вам нужно обрабатывать оба случая.
в чем преимущество использования std::optional против, например, возвращающего -1, или nullptr из функции, если не удается вычислить результат?
Откуда вы знаете, что такое условие ошибки? Это 0
, -1
, MAX_INT
, nullptr
или что-то еще? Если у меня есть unsigned int
и int
возвращаемое значение, и int
возвращаемая ранее версия -1
, следует ли вам изменить их оба на MAX_INT
или заставить их возвращать разные значения? std::optional
позволяет избежать проблемы.
И что более важно для меня, почему std::optional не был разработан как монада, есть ли причина?
Есть ли в C монады на данный момент? До тех пор, пока абстракция, отличная от контейнерной, на самом деле не существует способа добавить эту функциональность.
Комментарии:
1. Я бы сказал, что в C есть монады (например, необязательные <T> и векторные <T>). Чего ему не хватает, так это хорошего синтаксиса для выполнения над ними монадических операций, но все же может быть полезно думать о них как о монадах.
2. @toth конечно, операции (и тот факт, что они подчиняются законам монады) являются важной частью монады, а не типа? Без операций optional<T> — это просто тип.
Ответ №3:
Вы можете определить bind
и return
over std::optional
, так что в этом смысле это все еще монада.
Например, возможный bind
template<typename T1, typename T2>
std::optional<T2> bind(std::optional<T1> a, std::function< std::optional<T2>(T1)> f) {
if(a.has_value()) return f(a.value());
return std::optional<T2>{};
}
На самом деле, вероятно, полезно определить это.
Что касается того, почему стандартная библиотека не поставляется с этим или чем-то подобным, я думаю, что ответ является одним из предпочтительных стилей в языке.
Комментарии:
1. Это не сработает. Вы хотите что-то вроде
template<typename T1, typename F> auto bind(std::optional<T1> a, F f) -> std::optional<std::decay_t<decltype(f(*a))>>;
2. @T.C., это правда, что в моей версии компилятор не может вывести T2, поэтому вам нужно указывать его всякий раз, когда вы вызываете bind, но я бы сказал, что это все еще считается рабочим. Я согласен, что на практике ваша версия лучше, поскольку она выводит типы и более эффективна (нет необходимости использовать std::function, если вы этого не хотите), но, по крайней мере, мне сложнее определить, каким
f
должен быть тип, глядя на объявление.3. @T.C., также я считаю, что вам не нужен
std::optional
тип возвращаемого значения в конце.f
In bind должен возвращать astd::optional
, для которого ваша подпись типа будет правильнойfmap
.4. Хороший момент для второго. Это ошибка. (Если вам нужны явно указанные параметры, по крайней мере, измените порядок параметров вашего шаблона и перенесите тип второго параметра функции в неразведенный контекст, чтобы
T1
его можно было вывести.)