C# 状态设计模式的功能等价

C# 状态设计模式的功能等价,c#,oop,design-patterns,haskell,functional-programming,C#,Oop,Design Patterns,Haskell,Functional Programming,状态设计模式的函数编程等价物是什么?或者更具体地说,状态设计模式将如何转化为FP?可能是使用带有自定义修饰符和访问器的状态单子?我认为状态模式没有纯粹的功能等价物。因为纯函数式编程没有状态和时间的概念。状态模式本质上是关于状态和时间的。但我认为非纯函数等价物是存在的,它是无限的。您可以使用C#yield实现它。此模式是使用计算 环境tha使用状态扩充代码 下面是Haskell中的一个实现 一些助手: import Control.Monad.Trans.State import Control.

状态设计模式的函数编程等价物是什么?或者更具体地说,状态设计模式将如何转化为FP?

可能是使用带有自定义修饰符和访问器的
状态单子?

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

此模式是使用计算 环境tha使用状态扩充代码

下面是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)
根据上述代码,main的输出为:

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

一种编码:

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
来存储状态或任何东西)。展开
新类型
,我们可以看到此类型的含义:

State = String -> IO (String -> IO (String -> IO (String -> ...
它接受一个字符串,执行一些I/O,并请求另一个字符串,等等

这是我在OO中最喜欢的抽象类模式编码:抽象类->类型,子类->该类型的元素

newtype状态
声明取代了抽象的
writeName
声明及其签名。我们没有传递一个
StateContext
,而是让它返回新状态。在
IO
中嵌入返回值表示允许新状态依赖于I/O。因为在本例中这在技术上不是必需的,所以我们可以使用更严格的类型

newtype State = State { unState :: String -> (State, IO ()) }
其中我们仍然可以表示这种计算,但状态序列是固定的,不允许依赖于输入。但让我们坚持原来的,更宽松的类型

对于“测试客户端”:

runState::State->[String]->IO()
运行状态s[]=返回()
运行状态s(x:xs)=do

s’同意,在我看来,似乎是对
状态的特殊使用。从没听说过单子?甚至有一种称为函数式反应式编程的方法来捕获时变状态。我不认为“has”是连接“函数式编程”和“状态”的合适词。我喜欢将其视为“模型”——我们可以通过建立状态含义的函数模型来进行状态计算。@Todd Monad是完全纯的。你可以携带任何一种状态。还有STM,它提供了可修改局部变量的概念。即使STM在某种意义上也是纯粹的,您可以证明,以指定方式使用STM的函数在引用上是透明的。不过State可能不是最流行的成语。@fuzzxl,我想你想的是
ST
,而不是
STM
@luqui:我认为“has”是一个可行的词,实际上,粗略地说就是“可供使用和操纵”。因此,纯语言有状态的概念,而非纯语言只有内在状态。因此,Haskell拥有比任何命令式语言都多得多的操作命令式计算的工具,这似乎是一个悖论。我不会说这是一种忠实的编码:这里我们必须在一个地方声明所有模式(
数据模式
),而在wikipedia示例中,声明可以模块化组合,这是ML风格语言中对封闭数据类型的标准转换。显然,我们可以通过函数或类型类使用开放数据类型,但我认为这与这个问题无关。我很好奇什么是标准翻译,以及标准是什么意思。我认为惯用的做法是将具有多个变体的对象转换为代数数据类型。P.S。您还需要捕获计数器切换语义。无论如何,我认为这种编码方式只适用于封装抽象行为的真正的OO惯用类。据称OO代码中数量令人沮丧的“类”与Don使用的笨拙翻译风格更为接近,因此从被转换回他们最初想要的状态中获益匪浅。。。
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" ]