gpt4 book ai didi

haskell - 我可以为 IO Monad 取 "snapshots"吗?

转载 作者:行者123 更新时间:2023-12-02 15:12:33 25 4
gpt4 key购买 nike

我目前正在编写一个基于 Arrows 的 FRP 库(即 timeless )。但是,我遇到了一个问题:

如果我在箭头内包含一个 IO 操作(在本例中为 Signal s IO a b,这是一个 Kleisli 箭头),我想采取一个“最终返回值的“快照”,而不是每次都运行该操作。例如,我有一个涉及读取文件并解析为某种数据结构的操作,当前该操作正在运行每一帧更新。我尝试了一下利用 Haskell 的惰性求值来防止它一次又一次地运行,但没有成功。

从概念上讲,Signal 基本上(但不完全是)

a -> IO (b, Signal)

每次更新,信号本身都会被新信号替换。现在,我认为如果我提供一个 IO a 类型的 IO 操作(使用 Kleisli 箭头),我可以以某种方式用某些东西替换 Signal else 保存前一个操作的最终结果。但是,我找不到一种方法来做到这一点,因为我无法从 IO 中提取任何内容,并且简单地将信号替换为常量信号似乎并不能阻止重新评估操作。

这是一个最小的测试程序:

{-# LANGUAGE Arrows #-}

module Main where

import FRP.Timeless
import Debug.Trace

s1 :: (Monad m) => Signal s m a Int
s1 = mkConst $ trace "Signal 1" $ Just 5
s2 :: (Monad m) => Signal s m Int Int
s2 = arr $ trace "Signal 2" (+1)
s3 :: (Monad m) => Signal s m a ()
s3 = arr $ \_ -> ()

sc = mkKleisli_ $ \_ -> do
putStrLn "SC"
readFile "test.txt"
sp = mkKleisli_ putStrLn

box :: Signal s IO () ()
box = proc _ -> do
file <- sc -< ()
sp -< file
returnA -< ()

box2 = proc _ -> do
box -< ()

main = do
runBox clockSession_ box2

这里,sc 读取文件“Test.txt”。每次都会对其进行评估。我想找到一种方法,只评估一次,并保持值(value)。

顺便说一句,unsafePerformIO 可能会工作,但是,正如其名称所暗示的,它可能是“不安全的”,所以我不想使用它

最佳答案

好的,我想我可以通过添加这个信号来让它工作:

onceSwitch = mkPureN $ (\_ -> (Just (), mkEmpty))

我将切换概括为以下函数(并添加到 timelessPrefab 中):

occursFor :: b -> Int -> Signal s m a b
occursFor b n
| n == 0 = mkEmpty
| n > 0 = mkPureN $ \_ -> (Just b, occursFor b $ n-1)
| otherwise = error "[ERROR] occursFor: Nothing occurs for less than zero times!"

第一次运行时其输出为(),然后禁止,此信号:

onceIO = SGen $ f
where
f _ ma = return (ma, SArr $ const ma)

第一次运行后成为常数。像这样链接 IO 操作:

file <- onceIO <<< sc <<< () `occursFor` 1 -< ()

似乎可以正常工作。 (更新:现在使用 occurrsFor)

经过一番调整,看起来像这样。请注意,timeless 的 API 随着我的开发而发生剧烈变化,但我在下面使用的功能很可能不会改变。无论如何,同样的事情也适用于 netwire,它是 timeless 的起源,但有一些细微的变化。如果您需要制作一些应用程序,请暂时使用它。

{-# LANGUAGE Arrows #-}

module Main where

import FRP.Timeless
import Debug.Trace

sc = mkKleisli_ $ \_ -> do
putStrLn "SC"
return "A"
sp = mkKleisli_ putStrLn

box :: Signal s IO () ()
box = proc _ -> do
file <- snapOnce <<< sc <<< inhibitsAfter 1 -< ()
sp -< file
returnA -< ()

box2 = proc _ -> do
box -< ()

main = do
runBox clockSession_ box2

关于haskell - 我可以为 IO Monad 取 "snapshots"吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33059636/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com