String.IsNullOrEmpty монада - PullRequest
       153

String.IsNullOrEmpty монада

1 голос
/ 14 июля 2020

В последнее время я погружаюсь в увлекательный мир функционального программирования, в основном благодаря приобретению опыта работы с платформами FP, такими как React, и чтению блогов, подобных https://blog.ploeh.dk/. Как программист, в первую очередь императивный, это был интересный переход, но я все еще пытаюсь замочить себе ноги.

Я немного устал от использования string.IsNullOrEmpty как такового. Большую часть времени я засыпаю свой код такими выражениями, как

_ = string.IsNullOrEmpty(str) ? "default text here" : str;

, что не так уж плохо, как кажется, но, скажем, я хотел связать кучу параметров за этим нулем, например

_ = string.IsNullOrEmpty(str) ? (
    util.TryGrabbingMeAnother() ??
    "default text here") : str;

Уф. Я бы предпочел что-то вроде этого -

_ = monad.NonEmptyOrNull(str) ??
    util.TryGrabbingMeAnother() ??
    "default text here";

Как видно из примера, я использую функцию, которую я называю монадой, чтобы помочь уменьшить string.IsNullOrEmpty до операции с цепочкой нулей :

public string NonEmptyOrNull(string source) =>
    string.IsNullOrEmpty(source) ? null : source;

У меня вопрос, это правильная терминология? Я знаю, что Nullable<T> можно рассматривать как монаду (см. Может ли Nullable использоваться как функтор в C#? и Monad на простом английском sh? (Для программиста OOP с без фона FP) ). Эти материалы являются хорошими справочными материалами, но у меня все еще недостаточно интуитивного понимания предмета, чтобы понять, не просто ли я здесь запутываю или непоследователен. Например, я знаю, что монады должны включать объединение функций, как у меня выше, но они также являются «усилителями типов» - так что мой маленький пример, кажется, ведет себя как монада для включения цепочки, но кажется например, преобразование null / empty в просто null - это сокращение , а не усиление, поэтому я сомневаюсь, действительно ли это является монадой. Итак, для этого конкретного приложения, может ли кто-нибудь, имеющий немного больше опыта с FP, сказать мне, правильно ли называть NonEmptyOrNull монадой, и почему или почему нет?

Ответы [ 3 ]

1 голос
/ 14 июля 2020

Монада - это тройка, состоящая из:

  • Конструктора типа с одним аргументом M
  • Функция unit типа a -> M a
  • Функция join типа M (M a) -> a

, которая удовлетворяет монаде l aws.

Конструктор типа - это функция уровня типа, которая принимает число типов аргументы и возвращает тип. C# не имеет этой функции напрямую, но при кодировании монад вам нужен тип generi c с одним аргументом, например List<T>, Task<T> et c. Поэтому для некоторого generi c type M вам понадобятся две функции, которые создают экземпляр generi c типа из одного значения и «сглаживают» вложенный экземпляр типа. Например, для List<T>:

public static List<T> unit<T>(T value) { return new List<T> { value }; }
public static List<T> join<T>(List<List<T>> l) { return l.SelectMany(l => l); }

Из этого определения вы можете видеть, что отдельная функция не может удовлетворять определению монады, поэтому ваш пример не является примером монады.

Согласно этому определению, Nullable<T> также не имеет экземпляра монады, так как вложенный тип Nullable<Nullable<T>> не может быть построен, поэтому join не может быть реализован.

1 голос
/ 19 июля 2020

Это больше похоже на операцию filter . В C# вы бы идиоматически назвали его Where. Возможно, будет легче увидеть, если мы сделаем различие между отсутствующими и заполненными значениями более явным, что мы можем сделать с контейнером Maybe :

public static Maybe<T> Where<T>(
    this Maybe<T> source,
    Func<T, bool> predicate)
{
    return source.SelectMany(x => predicate(x) ? x.ToMaybe() : Maybe.Empty<T>());
}

Их всего несколько контейнеры , поддерживающие фильтрацию. Двумя наиболее распространенными являются Maybe (AKA Option) и различные коллекции (например, IEnumerable<T>).

In Haskell (который имеет более мощную систему типов, чем C#) это разрешено через класс с именем MonadPlus, но я думаю, что класса типа Alternative на самом деле должно быть достаточно для реализации фильтрации. Alternative описывается как моноид на аппликативных функторах. Я не уверен, что это особенно полезно.

С помощью описанного выше метода Where, вы можете пропустить Maybe значения через проверки типа IsNullOrEmpty следующим образом:

var m = "foo".ToMaybe();
var inspected = m.Where(s => !string.IsNullOrEmpty(s));

Это позволит m пройти без изменений, в то время как следующее не будет:

var m = "".ToMaybe();
var inspected = m.Where(s => !string.IsNullOrEmpty(s));

Вы можете сделать то же самое с Nullable<T>, но я оставлю это как упражнение ?

Также возможно, что вы могли бы сделать это с новыми ссылочными типами, допускающими значение NULL, языковыми особенностями C# 8, но я еще не пробовал.

0 голосов
/ 14 июля 2020

Я считаю, что это обычно решается в парадигме FP на шаг впереди проверки null. Значение str никогда не должно быть null. Вместо этого исходный метод должен возвращать пустую коллекцию. Таким образом, цепочка методов не должна подтверждать значение null. Следующая операция не будет выполнена, поскольку нет элементов, с которыми можно было бы работать.

Есть несколько ссылок, которые вы можете найти. связанные с этим на инте rnet. https://www.informit.com/articles/article.aspx?p=2133373&seqNum=5 - это то, что я мог быстро схватить

Я узнал об этом из курса Зорана Хорват в Pluralsight. Если у вас есть доступ, проверьте его. Название курса - «Шаблоны тактического проектирования в. NET: поток управления», а модуль - «Шаблоны с нулевым объектом и особый случай».

Проявляя интерес к FP, Зоран Хорват также имеет другие курсы, которые помогают преобразовать или сделать объектно-ориентированный код более функциональным. Я очень рад ответить здесь, потому что в последнее время я тоже изучаю FP. Удачи!

...