В чем разница между разными порядками одних и тех же преобразователей монад?

Я склонен всегда использовать структурированный C++ пути к этому виду инициализации. Заметьте, что существенно, это не отличается, чем решение Altan. Программисту на C++ это просто выражает намерение немного лучше и могло бы быть более легким портативным устройством к другим типам данных. В этом экземпляре, функция C++ generate_n экспрессы точно, что Вы хотите:

struct rnd_gen {
    rnd_gen(char const* range = "abcdefghijklmnopqrstuvwxyz0123456789")
        : range(range), len(std::strlen(range)) { }

    char operator ()() const {
        return range[static_cast(std::rand() * (1.0 / (RAND_MAX + 1.0 )) * len)];
    }
private:
    char const* range;
    std::size_t len;
};

std::generate_n(s, len, rnd_gen());
s[len] = '\0';

Между прочим, читайте эссе Julienne’s на том, почему это вычисление индекса предпочтено по более простым методам (как взятие модуля).

25
задан Keith Holman 26 February 2011 в 18:58
поделиться

2 ответа

Чтобы дополнить другие ответы, я хотел бы описать, как это выяснить в общем случае. То есть, учитывая два преобразователя, какова семантика их двух комбинаций?

У меня было много проблем с этим вопросом, когда я начал использовать монадные преобразователи в проекте разбора на прошлой неделе. Мой подход состоял в том, чтобы создать таблицу преобразованных типов, к которой я обращаюсь всякий раз, когда я не уверен. Вот как я это сделал:

Шаг 1 : создайте таблицу основных типов монад и соответствующих им типов преобразователей:

transformer           type                  base type (+ parameter order)

---------------------------------------------------------------

MaybeT   m a        m (Maybe a)            b.    Maybe b

StateT s m a        s -> m (a, s)          t b.  t -> (b, t)

ListT    m a        m [a]                  b.    [] b

ErrorT e m a        m (Either e a)         f b.  Either f b

... etc. ...

Шаг 2: примените каждый монадный преобразователь к каждой из базовых монад, подставив вместо параметра типа m:

inner         outer         combined type

Maybe         MaybeT        Maybe (Maybe a)
Maybe         StateT        s -> Maybe (a, s)      --  <==  this !!
... etc. ...

State         MaybeT        t -> (Maybe a, t)      --  <== and this !!
State         StateT        s -> t -> ((a, s), t)
... etc. ...

(Этот шаг немного болезненный, поскольку существует квадратичное число комбинации ... но это было хорошее упражнение для меня, и мне нужно было сделать это только один раз.) Ключ для меня здесь в том, что я написал комбинированные типы развернутыми - без всех этих раздражающие обертки MaybeT, StateT и т. д. Мне намного проще смотреть и думать о типах без шаблона.

Чтобы ответить на ваш исходный вопрос, эта диаграмма показывает, что:

  • MaybeT + State :: t -> (Maybe a, t) вычисление с сохранением состояния, в котором не может быть значения, но всегда будет (возможно, изменено) выход состояния

  • StateT + Maybe :: s -> Maybe (a, s) вычисление, при котором и состояние, и значение могут отсутствовать

13
ответ дан 28 November 2019 в 20:53
поделиться

Вы сможете ответить на вопрос самостоятельно, если попытаетесь написать «запускающие» функции для обеих версий - у меня не установлены MTL + -трансформаторы, поэтому я не могу сделать это сам. Один вернет (может быть, состояние) другой Может быть (состояние) .

Редактировать - я обрезал свой ответ, так как он добавляет детали, которые могут сбить с толку. Ответ Джона ударяет гвоздь по голове.

4
ответ дан 28 November 2019 в 20:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: