Как использовать std::необязательно в C

#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 должен возвращать a std::optional , для которого ваша подпись типа будет правильной fmap .

4. Хороший момент для второго. Это ошибка. (Если вам нужны явно указанные параметры, по крайней мере, измените порядок параметров вашего шаблона и перенесите тип второго параметра функции в неразведенный контекст, чтобы T1 его можно было вывести.)