【发布时间】:2011-09-13 01:38:40
【问题描述】:
状态设计模式的函数式编程等价物是什么?或者更具体地说,State 设计模式的this Wikipedia example 将如何转化为 FP?
【问题讨论】:
标签: c# oop design-patterns haskell functional-programming
状态设计模式的函数式编程等价物是什么?或者更具体地说,State 设计模式的this Wikipedia example 将如何转化为 FP?
【问题讨论】:
标签: c# oop design-patterns haskell functional-programming
一种编码:
import Data.Char (toUpper, toLower)
newtype State = State { unState :: String -> IO State }
stateA :: State
stateA = State $ \name -> do
putStrLn (map toLower name)
return stateB
stateB :: State
stateB = go 2
where
go 0 = stateA
go n = State $ \name -> do
putStrLn (map toUpper name)
return $ go (n-1)
不要被IO 愚弄,这是对该模式的纯粹翻译(我们没有使用IORef 来存储状态或任何东西)。展开newtype,我们看看这个类型是什么意思:
State = String -> IO (String -> IO (String -> IO (String -> ...
它需要一个字符串,执行一些 I/O 并请求另一个字符串,等等。
这是我最喜欢的 OO 中抽象类模式的编码:抽象类 -> 类型,子类 -> 该类型的元素。
newtype State 声明代替了摘要 writeName 声明及其签名。我们没有传递StateContext 来分配新状态,而是让它返回新状态。将返回值嵌入IO 表示允许新状态依赖于 I/O。由于在本例中这在技术上不是必需的,因此我们可以使用更严格的类型
newtype State = State { unState :: String -> (State, IO ()) }
我们仍然可以表达这个计算,但是状态序列是固定的,不允许依赖于输入。但我们还是坚持原来的,更宽松的类型。
对于“测试客户端”:
runState :: State -> [String] -> IO ()
runState s [] = return ()
runState s (x:xs) = do
s' <- unState s x
runState s' xs
testClientState :: IO ()
testClientState = runState stateA
[ "Monday"
, "Tuesday"
, "Wednesday"
, "Thursday"
, "Saturday"
, "Sunday" ]
【讨论】:
此模式是使用State monad 的示例,这是一个计算 使用状态增强代码的环境。
这是 Haskell 中的一个实现。
一些帮手:
import Control.Monad.Trans.State
import Control.Monad.IO.Class
import Data.Char
程序的两种运行模式
data Mode = A | B
这种模式下的有状态计算类型,增加了一个计数器。
type StateM a = StateT (Int, Mode) IO a
write函数,StateM上下文中的一个函数, 根据有状态模式改变其行为:
writeName :: String -> StateM ()
writeName s = do
(n,mode) <- get
case mode of
A -> do liftIO (putStrLn (map toLower s))
put (0,B)
B -> do let n' = n + 1
liftIO (putStrLn (map toUpper s))
if n' > 1 then put (n', A)
else put (n', B)
运行程序,最初在状态 A 中启动有状态计算
main = flip runStateT (0, A) $ do
writeName "Monday"
writeName "Tuesday"
writeName "Wednesday"
writeName "Thursday"
writeName "Saturday"
writeName "Sunday"
从上面的代码来看,main的输出是:
monday
TUESDAY
WEDNESDAY
thursday
SATURDAY
SUNDAY
请注意,这是一个纯粹的功能解决方案。此程序中没有可变的或破坏性的更新。相反,状态单子通过计算线程化所需的模式。
【讨论】:
data Mode),而在维基百科示例中,声明可以模块化组合。
我认为状态模式没有纯粹的功能等价物。因为纯函数式编程没有状态和时间的概念。状态模式本质上是关于状态和时间的。但我认为存在非纯功能等价物,它是无限惰性评估流。您可以使用 C# yield 来实现它。
【讨论】:
ST,而不是STM。
也许将 State monad 与自定义修饰符和访问器结合使用?
【讨论】:
State monad 的特殊用途。