Ваш пример содержит несколько вещей, которые могли бы работать по-другому на функциональном языке:
- Класс изменчив - в функциональных языках вы бы использовали неизменный тип
- Вы используете
current_time
для получения текущего времени, но это не чистая функция (это зависит от некоторого глобального изменяющегося состояния). В чистых функциональных языках (Haskell) это недопустимо (и вы должны использовать монады), но большинство нечистых функциональных языков (F #, OCaml) позволяют это.
- Ваша функция
main
использует цикл - циклы, как правило, не рекомендуется на функциональных языках (хотя некоторые их поддерживают).
Идиоматическое решение F # будет иметь дело с первым и последним пунктом, как это:
let currentTime() =
System.DateTime.Now
type State(startTime) =
static member Start() =
State(currentTime())
member x.IsCompleted =
(currentTime() - startTime).TotalSeconds > 30.0
member x.Progress =
(currentTime() - startTime).TotalSeconds / 30.0
let main() =
let s = State.Start()
let rec loop () =
if not s.IsCompleted then
printf "%A" s.Progress
loop ()
loop ()
printf "finished"
Тип State
является неизменным в том смысле, что он никогда не изменяет значение своего локального поля. Это не чисто функционально, потому что это зависит от (изменяющегося) текущего времени, но это не проблема в F # (вы просто должны знать об этом). Если вам нужен какой-то метод, который изменяет состояние (чего у вас нет), то метод вернет новый экземпляр State
(точно так же, как .NET string
).
Функция main
написана с использованием рекурсии вместо цикла - в этом случае это не имеет значения (цикл был бы также хорош в F #). Смысл использования рекурсии в том, что вы можете передать текущее состояние в качестве аргумента и использовать новый экземпляр при выполнении рекурсивного вызова (который существенно меняет текущее состояние во время вычисления).