Haskell 自动重新计算结果
基本上,我希望能够编写如下代码:Haskell 自动重新计算结果,haskell,reactive-programming,Haskell,Reactive Programming,基本上,我希望能够编写如下代码: main = do x <- newVal (2 :: Int) y <- newVal (3 :: Int) z <- newFunc (x, y) (\(a,b) -> a * b) r1 <- readVal z print r1 -- prints 6 (2 * 3) setVal x 5 r2 <- readVal z print r2 -- prints 15 (5 * 3) m
main = do
x <- newVal (2 :: Int)
y <- newVal (3 :: Int)
z <- newFunc (x, y) (\(a,b) -> a * b)
r1 <- readVal z
print r1 -- prints 6 (2 * 3)
setVal x 5
r2 <- readVal z
print r2 -- prints 15 (5 * 3)
main=do
x这几乎就是STRef
和IORef
的功能,除非我在上面的评论中提到,否则您无法获得完全多态的newFunc
。你必须做一些有助于提升的事情
import Data.IORef
main = do
x <- newVal (2 :: Int)
y <- newVal (3 :: Int)
let z = liftIORef2 (x, y) (\(a,b) -> a * b)
r1 <- readVal z
print r1 -- prints 6 (2 * 3)
setVal x 5
r2 <- readVal z
print r2 -- prints 15 (5 * 3)
liftIORef2 (a, b) f = do
a' <- readIORef a
b' <- readIORef b
return (f (a', b'))
newVal = newIORef
setVal = writeIORef
readVal = id
*Main> main
6
15
import Data.IORef
main=do
希望有人能给你一个FRP答案,现在我将向你展示如何用STM制作反应系统
首先,我们需要显式声明事务变量,并设置生产者和消费者。本例中的“生产者”是您的newFunc
,它读取x
和y
以产生新的z
。“消费者”读取z
,并在更改后打印
import Control.Concurrent.STM
import Control.Concurrent
import Control.Monad
f = do
x <- newTVarIO 2
y <- newTVarIO 3
z <- newTVarIO 0
forkIO $ newFunc 2 3 (x,y) z
loop z 0
这种简单的读取比较模式{retry或compute}功能强大,正是newFunc
所需要的。我们将读取所有值,并在输入未更改且结果正确的情况下重试(调整此值以满足您的需要)
newFunc::Int->Int->(TVar Int,TVar Int)->TVar Int->IO()
newFunc xV yV(x,y)z=原子级$do
newX您可以将您的程序视为增量计算的一个示例,下面是一个使用库的解决方案,它可以用来表示此类增量计算问题
import Control.Monad.Adaptive (newMod, readMod, inM, change, propagate, run)
main :: IO ()
main = run $ do
x <- newMod $ return 2
y <- newMod $ return 3
z <- newMod $ do
a <- readMod x
b <- readMod y
return (a * b)
newMod $ do -- For observing 'z'
r <- readMod z
inM $ print r
-- prints 6 (2 * 3)
change x 5
propagate -- prints 15 (5 * 3)
import Control.Monad.Adaptive(newMod、readMod、inM、更改、传播、运行)
main::IO()
main=run$do
你到底想实现什么?什么是newVal
,newFunc
,setVal
等等?@Sibi根据我的反应式编程经验,我猜,newVal
创建了一个可以/将要改变的值(想想电子表格的一个单元格),而newFunc
创建了一个“公式”并将结果存储在z
中,以便在setVal
anything@sibijozefg是正确的。你定义它们,它们只是为了说明的目的。预期的输出应该清楚地表明我正在努力实现的目标,我不介意你提出一个稍微有点小的方法different@Clinton:您必须接受对语法的一些更改,因为请注意,x@TomEllis中的值是No,newVal中的x将是IOref或STref,不是实际值。语法确实有道理。
newFunc :: Int -> Int -> (TVar Int , TVar Int) -> TVar Int -> IO ()
newFunc xV yV (x, y) z = atomically $ do
newX <- readTVar x
newY <- readTVar y
currZ <- readTVar z
let result = newX * newY
when (newX == xV && newY == yV && currZ == result) retry
writeTVar z result
import Control.Monad.Adaptive (newMod, readMod, inM, change, propagate, run)
main :: IO ()
main = run $ do
x <- newMod $ return 2
y <- newMod $ return 3
z <- newMod $ do
a <- readMod x
b <- readMod y
return (a * b)
newMod $ do -- For observing 'z'
r <- readMod z
inM $ print r
-- prints 6 (2 * 3)
change x 5
propagate -- prints 15 (5 * 3)