Давайте посмотрим на вашем C++ цикл:
while (state == true) {
a = function1();
b = function2();
state = function3();
}
Haskell является чисто функциональным языком, поэтому он не будет бороться с нами столько, сколько (и в результате код будет более полезным, как сам по себе и как упражнение для изучения Haskell), если мы попытаемся сделать это без побочных эффектов и не будем использовать монады, чтобы они выглядели так, как будто мы используем побочные эффекты.
Давайте начнем с этой структурой
while (state == true) {
<<do stuff that updates state>>
}
В Haskell мы, очевидно, не собирается проверять переменную против true
как условие цикла, потому что он не может изменить его значение [1] и мы d либо оценивать тело цикла навсегда, либо никогда. Поэтому вместо того, мы хотим, чтобы оценить функцию, которая возвращает логическое значение, на каком-то аргументе:
while (check something == True) {
<<do stuff that updates state>>
}
Ну, теперь мы не имеем state
переменных, так что «делать такие вещи, которые обновляют состояние» выглядя довольно бессмысленно. И у нас нет something
, чтобы перейти на check
. Давайте подумаем об этом немного больше. Мы хотим, чтобы something
был проверен в зависимости от того, что делает бит «do stuff». У нас нет побочных эффектов, поэтому означает, что something
должен быть (или быть полученным), возвращенным из «do stuff». «делать вещи» также необходимо взять что-то, что меняется в качестве аргумента, или оно просто вернет ту же самую вещь навсегда, что также бессмысленно. Нам также нужно вернуть значение из всего этого, иначе мы просто сжигаем циклы процессора (опять же, без побочных эффектов нет смысла запускать какую-либо функцию, если мы не будем использовать ее выход каким-либо образом, и есть еще меньше очков функция, если мы никогда не будем использовать ее выход).
Так как о чем-то вроде этого:
while check func state =
let next_state = func state in
if check next_state
then while check func next_state
else next_state
Давайте попробуем в GHCi:
*Main> while (<20) (+1) 0
20
Это результат применения (+1) несколько раз, пока результат меньше 20, начиная с 0.
*Main> while ((<20) . length) (++ "zob") ""
"zobzobzobzobzobzobzob"
Это результат повторного объединения «zob», в то время как результат th меньше 20, начиная с пустой строки.
Итак, вы можете видеть, что я определил функцию, которая является (вроде бит) аналогичной петле while
с императивных языков. Нам даже не нужен специальный синтаксис цикла! (что является реальной причиной того, что у Haskell нет такого синтаксиса, если вам нужна такая вещь, вы можете выразить ее как функцию). Это не единственный способ сделать это, и опытные программисты Haskell, вероятно, будут использовать другие стандартные библиотечные функции для выполнения такой работы, вместо того, чтобы писать while
.
Но я думаю, что полезно узнать, как вы можете выразить подобные вещи в Haskell. Это показывает, что вы не можете переводить такие вещи, как императивные петли напрямую в Haskell; Я не закончил перевод вашего цикла с точки зрения моего while
, потому что он заканчивается довольно бессмысленным; вы никогда не используете результат function1
или function2
, они вызываются без аргументов, поэтому они всегда возвращают одно и то же на каждой итерации, и function3
также всегда возвращает то же самое, и может возвращать только true
или false
, чтобы вызвать while
для продолжения цикла или остановки, без получения информации.
Предположительно, в программе на C++ все они используют побочные эффекты, чтобы на самом деле выполнить определенную работу. Если они работают в памяти, тогда вам нужно перевести большую часть вашей программы сразу в Haskell для перевода этого цикла, чтобы иметь смысл. Если эти функции выполняют IO, вам нужно сделать это в монаде IO
в Haskell, для которого моя функция while
не работает, но вы можете сделать что-то подобное.
[1] Как и в сторону, стоит попробовать, чтобы понять, что «вы не можете изменить переменные» в Haskell это не просто произвольное ограничение, равно как и его просто приемлемым компромиссом для преимуществ чистота, это концепция, что не имеет смысла, как Haskell хочет, чтобы вы подумали о коде Haskell. Вы записываете выражения, которые являются результатом оценки функций по определенным аргументам: в f x = x + 1
вы говорите, что f x
isx + 1
. Если вы действительно думаете об этом так, а не думаете, что «f принимает x, затем добавляет его к нему, а затем возвращает результат», тогда понятие «иметь побочные эффекты» даже не применяется; как что-то существующее и равное чему-то другому каким-то образом меняет переменную или имеет какой-то другой побочный эффект?
Код, который вы отправили, по своей сути является обязательным. Хотя в Haskell можно писать код в императивном стиле, это обычно не лучший подход. Я думаю, вы должны начать с более высокого уровня концепции того, что делает код, и попытаться перевести это в функциональное решение. –
Вы правы ... Я все еще пытаюсь перевести мой образ мышления на C++ на функциональный язык. Но я не могу придумать другого способа сделать это без какой-то петли.В моей программе некоторые функции нужно вызывать несколько раз, пока не будут выполнены все условия. –
Вы должны сказать нам, что вы _actually_ пытаетесь сделать здесь, чтобы мы могли помочь вам переработать его в функциональное решение. –