Монада State по существу работает с типом 'state -> 'res * 'state
, который представляет вычисление, которое принимает некоторое начальное состояние и выдает результат (вместе с новым значением состояния).
Если вы спрашиваете, имеет ли какое-то значение, даем ли мы какое-то специальное имя этому типу (например, State<'state, 'res>
), тогда ответ на самом деле не имеет значения. Единственная цель присвоения некоторого специального имени типу состоит в том, чтобы сделать код более читабельным. Например, давайте рассмотрим две возможные сигнатуры типов в следующем примере:
let foo n = state {
let! m = getState()
do! setState(m + 1)
return sprintf "Result: %d" (n * m) }
// Using State<'state, 'res> type:
val foo : int -> State<int, string>
// Using the underlying representation:
val foo : int -> int -> int * state
Первый тип подписи более четко говорит о том, что мы пишем функцию в некоторой монаде. Второй пример - это просто функция, которая принимает два значения int
. Я думаю, что главное преимущество первого состоит в том, что вы можете легче понять, что тип может использоваться из других монадических вычислений (написанных с использованием state { ... }
).
Однако, как я уже отметил, это не техническое требование. Люди, вероятно, используют этот стиль, потому что многие монады происходят из Хаскелла, где монады связаны с типом (например, State<'state, 'res>
), а не с компилятором (например, state
). ), поэтому неплохо определить новый тип для каждой монады в Haskell.