状态设计模式的功能等价

时间:2011-06-11 14:10:37

标签: c# oop design-patterns haskell functional-programming

与州设计模式相同的函数式编程是什么?或者更具体地说,状态设计模式的this Wikipedia example将如何转换为FP?

4 个答案:

答案 0 :(得分:7)

这种模式是使用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

写入函数,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

请注意,这是一个纯功能解决方案。此程序中没有可变或破坏性的更新。相反,状态monad通过计算线程化所需的模式。

答案 1 :(得分:5)

一种编码:

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抽象类模式编码:abstract class - &gt;类型,子类 - &gt;那种类型的元素。

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" ]

答案 2 :(得分:1)

也许将State monad与自定义修饰符和访问器结合使用?

答案 3 :(得分:-3)

我认为状态模式没有纯粹的功能等价物。因为纯函数式编程没有状态和时间的概念。状态模式本质上是关于状态和时间。但我认为非纯函数等价物存在,它是无限懒惰的评估流。您可以使用C#yield实现它。