首先,让我们考虑一些事情。
-
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 中,您必须显式地对状态变化进行建模。您可以使用“State Monad”让事情变得更漂亮,但您应该首先了解传递状态的概念。