Обычный способ написания является создание функции с локального состояния захваченного в затворе:
let getNextAlias =
let count = ref 0
(fun() ->
count := !count + 1;
sprintf "t%d" (!count))
Тип getNextAlias
является просто unit -> string
и когда вы вызываете его повторно, он возвращает строки «t1», «t2», ... Это зависит от изменяемого состояния, но изменчивое состояние скрыто от пользователя.
Относительно того, можете ли вы сделать это без изменяемого состояния - простой ответ НЕТ, потому что, когда вы вызываете чисто функциональную функцию с тем же параметром дважды, он должен возвращать тот же результат. Таким образом, вы должны были бы написать что-то со следующей структурой:
let alias, state1 = getNextAlias state0
printf "first alias %s" alias
let alias, state2 = getNextAlias state1
printf "second alias %s" alias
// ...
Как вы можете видеть, вы должны держать некоторое состояние и поддерживать его на протяжении всего кода. В F # стандартным способом борьбы с этим является использование изменчивого состояния. В Haskell вы можете использовать State monad, что позволяет скрыть передачу состояния. Используя реализацию from this question, вы могли бы написать что-то вроде:
let getNextAlias = state {
let! n = getState
do! setState (n + 1)
return sprintf "t%d" n }
let program =
state {
let! alias1 = getNextAlias()
let! alias2 = getNextAlias()
// ...
}
execute progam 0 // execute with initial state
Это очень похоже на другие вычисления, такие как lazy
или seq
, на самом деле - вычисления в state { .. }
блоке имеют некоторое состояние, и вы можете выполнять их, обеспечивая начальное значение государства. Однако, если у вас нет веских причин требовать чисто функционального решения, я бы предпочел первую версию для практического программирования F #.
Это полезно. Вы видите какой-либо способ сделать это без объявления изменяемого состояния? – Daniel
Одно можно добавить: вы можете использовать 'incr count' вместо' count: =!count + 1' – Daniel
Я понимаю, что должно быть изменчивое состояние _somewhere_, но мне нравится, чтобы он был скрыт в предопределенном шаблоне (например, ленивый, seq). – Daniel