Прежде всего, давайте подумаем о нескольких вещах.
- Есть ли у
function1
побочные эффекты?
- Есть ли у
function2
побочные эффекты?
- Есть ли у
function3
побочные эффекты?
Ответом на все эти вопросы является совершенно очевидное ДА, потому что они не принимают никаких входных данных, и, по-видимому, существуют обстоятельства, которые заставляют вас проходить цикл while более одного раза (а не def function3(): return false
). Теперь давайте переделаем эти функции с явным состоянием.
s = initialState
sentinel = true
while(sentinel):
a,b,s,sentinel = function1(a,b,s,sentinel)
a,b,s,sentinel = function2(a,b,s,sentinel)
a,b,s,sentinel = function3(a,b,s,sentinel)
return a,b,s
Ну это довольно некрасиво. Мы абсолютно ничего не знаем ни о том, какие входные данные получает каждая функция, ни о том, как эти функции могут влиять на переменные a
, b
и sentinel
, ни о «любом другом состоянии», которое я просто смоделировал как s
.
Итак, давайте сделаем несколько предположений. Во-первых, я собираюсь предположить, что эти функции не зависят напрямую и никак не влияют на значения a
, b
и sentinel
. Однако они могут изменить «другое состояние». Итак, вот что мы получаем:
s = initState
sentinel = true
while (sentinel):
a,s2 = function1(s)
b,s3 = function2(s2)
sentinel,s4 = function(s3)
s = s4
return a,b,s
Обратите внимание, что я использовал временные переменные s2
, s3
и s4
, чтобы указать изменения, через которые проходит "другое состояние". Время Хаскеля. Нам нужна управляющая функция, которая будет вести себя как цикл while
.
myWhile :: s -- an initial state
-> (s -> (Bool, a, s)) -- given a state, produces a sentinel, a current result, and the next state
-> (a, s) -- the result, plus resultant state
myWhile s f = case f s of
(False, a, s') -> (a, s')
(True, _, s') -> myWhile s' f
Теперь, как можно использовать такую функцию? Итак, учитывая, что у нас есть функции:
function1 :: MyState -> (AType, MyState)
function2 :: MyState -> (BType, MyState)
function3 :: MyState -> (Bool, MyState)
Мы бы построили желаемый код следующим образом:
thatCodeBlockWeAreTryingToSimulate :: MyState -> ((AType, BType), MyState)
thatCodeBlockWeAreTryingToSimulate initState = myWhile initState f
where f :: MyState -> (Bool, (AType, BType), MyState)
f s = let (a, s2) = function1 s
(b, s3) = function2 s2
(sentinel, s4) = function3 s3
in (sentinel, (a, b), s4)
Обратите внимание, как это похоже на неуродливый код, похожий на python, приведенный выше.
Вы можете убедиться, что код, который я представил, хорошо типизирован, добавив function1 = undefined
и т. д. для трех функций, а также следующее в верхней части файла:
{-# LANGUAGE EmptyDataDecls #-}
data MyState
data AType
data BType
Вывод таков: в Haskell вы должны явно моделировать изменения состояния. Вы можете использовать «монаду состояния», чтобы сделать вещи немного красивее, но сначала вы должны понять идею передачи состояния.
person
Dan Burton
schedule
14.02.2012