【问题标题】:Sequential circuit with feedack loop in HaskellHaskell中带有反馈回路的时序电路
【发布时间】:2023-04-10 17:18:01
【问题描述】:

我想在 Haskell 中表示具有以下行为的电路:

电路有两个输入:

  • 数据输入
  • 和一个开关量输入

和一个输出。

  • 当开关=True则输出t=输入t
  • 当 switch = False,输出 t = 输出 t-1

我需要一种表示反馈循环和状态的方法。

我知道有几个库为这类事情提供抽象,但它们对我来说就像魔术一样。

有没有简单的建模方法?

编辑:

type Signal a = [a]

type Input   = Signal Int
type Output  = Signal Int
type State   = Int
type Switch = Signal Bool

delay :: a -> Signal a -> Signal a
delay = (:)

circuit :: State -> Input -> Switch -> Output
circuit s (i:is) (True:bs) =  i : circuit i is bs
circuit s (i:is) (False:bs) = s : circuit s is bs

我使用流来表示信号,并在 s 中明确地携带状态。但是,如果我想动态提取(查看)输出流中的元素怎么办?

这看起来像是 State Monad 可以解决的问题,但我找不到表示它的方法。

【问题讨论】:

  • 乍一看,这似乎可以解决问题:circuit switch input t = if switch then input t else input (t-1) ...它有 2 个输入,它应该遵守您的法律(当然我假设最后一部分 output (t) = output (t-1) 是一个错字)
  • @Carsten,哦,当然,非常优雅!
  • @Carsten,这不是错字,如果开关关闭,我希望我的电路在给定时间返回之前的输出,以及当前输入(然后将成为新的存储值)当开关打开时。困难在于需要反馈循环和存储状态的方法。
  • 抱歉,我误解了您的 t(这显然代表时间) - 但可惜您已经有了一个很好的答案:D
  • 我不确定您所说的“即时”是什么意思。你的意思是你有一些实时输入? Fwiw 这就是 FRP 的发明目的。

标签: loops haskell sequential feedback circuit


【解决方案1】:

值得一提的是:这个问题非常适合 Haskell 的一些独特而强大的抽象,例如 MonadArrow。但是这些都需要时间和经验来学习,而且我从你的措辞猜测你对它们不是很熟悉。如果您继续使用 Haskell,我建议您将来再次重新审视这个问题以获得启发。我不会花更多时间在这些事情上。

您可以简单地通过无限列表对离散的时变信号进行建模:

type Signal a = [a]

zeroS, oneS :: Signal Bool
zeroS = repeat False
oneS  = repeat True

您可以使用zipWith 逐点组合信号。例如:

andS :: Signal Bool -> Signal Bool -> Signal Bool
andS = zipWith (&&)

ghci> andS zeroS oneS
[False,False,False,False,False,False,False,False,...

您可以通过在列表开头使用 consing 将信号延迟 1 个时间单位。这需要信号的初始值。

delay :: a -> Signal a -> Signal a
delay x s = x : s
-- or just
-- delay = (:)

在您的问题中,您使用这种类型描述了一个函数:

circuit :: Signal Bool -> Signal Bool -> Signal Bool
circuit switch input = ...

您可以使用这些概念和递归来构建它。祝你好运!

【讨论】:

  • 我认为这模仿了我试图实现的行为
  • @fayonglin 这样理解真的很难——也许你可以编辑你的问题?
【解决方案2】:

好的,我想我终于知道如何为此使用 State Monad。

Import Control.Monad.State

type Stored a = a
type Input a = a
type Output a = a
type Switch = Bool

circuit :: Input a -> Switch -> State (Output a) (Stored a)
circuit input switch = 
    do store <- get
       if switch
       then put input >> return input
       else return store

example1 = do circuit 0 False
              circuit 2 False
              circuit 3 False

res1 = runState example1 $ 4

loopCircuit :: [(Input a, Switch)] -> State (Output a) [(Stored a)]
loopCircuit [] = return []
loopCircuit ((i,s):xs) = 
    do v  <- circuit i s 
       vs <- loopCircuit xs
       return (v:vs)

example2 = runState (loopCircuit [(0,True),(2,False),(3,True)]) 4

circuit 函数可以处理离散输入,而loopCircuit 可以处理输入流。

res1 = (4,4)
example2 = ([0,0,3],3)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-23
    • 1970-01-01
    • 2018-12-14
    • 1970-01-01
    相关资源
    最近更新 更多