- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
go
worker tail-recursive loop pattern似乎非常适合编写纯代码。为 ST
编写这种循环的等效方法是什么?单子(monad)?更具体地说,我想避免在循环迭代中分配新的堆。我的猜测是它涉及 CPS transformation
或 fixST
重写代码,以便在循环中更改的所有值都在每次迭代中传递,从而使寄存器位置(或溢出的情况下的堆栈)在迭代中可用于这些值。我在下面有一个简化的示例(不要尝试运行它 - 它可能会因段错误而崩溃!)涉及一个名为 findSnakes
的函数其中有一个 go
worker 模式,但不断变化的状态值不通过累加器参数传递:
{-# LANGUAGE BangPatterns #-}
module Test where
import Data.Vector.Unboxed.Mutable as MU
import Data.Vector.Unboxed as U hiding (mapM_)
import Control.Monad.ST as ST
import Control.Monad.Primitive (PrimState)
import Control.Monad as CM (when,forM_)
import Data.Int
type MVI1 s = MVector (PrimState (ST s)) Int
-- function to find previous y
findYP :: MVI1 s -> Int -> Int -> ST s Int
findYP fp k offset = do
y0 <- MU.unsafeRead fp (k+offset-1) >>= \x -> return $ 1+x
y1 <- MU.unsafeRead fp (k+offset+1)
if y0 > y1 then return y0
else return y1
{-#INLINE findYP #-}
findSnakes :: Vector Int32 -> MVI1 s -> Int -> Int -> (Int -> Int -> Int) -> ST s ()
findSnakes a fp !k !ct !op = go 0 k
where
offset=1+U.length a
go x k'
| x < ct = do
yp <- findYP fp k' offset
MU.unsafeWrite fp (k'+offset) (yp + k')
go (x+1) (op k' 1)
| otherwise = return ()
{-#INLINE findSnakes #-}
cmm
输出
ghc 7.6.1
(我对
cmm
的了解有限 - 如果我弄错了请纠正我),我看到了这种调用流程,在
s1tb_info
中有循环(这会导致每次迭代中的堆分配和堆检查):
findSnakes_info -> a1_r1qd_info -> $wa_r1qc_info (new stack allocation, SpLim check)
-> s1sy_info -> s1sj_info: if arg > 1 then s1w8_info else R1 (can't figure out
what that register points to)
-- I am guessing this one below is for go loop
s1w8_info -> s1w7_info (big heap allocation, HpLim check) -> s1tb_info: if arg >= 1
then s1td_info else R1
s1td_info (big heap allocation, HpLim check) -> if arg >= 1 then s1tb_info
(a loop) else s1tb_info (after executing a different block of code)
arg >= 1
在
cmm
代码是确定是否
go
循环是否已终止。如果这是正确的,似乎除非
go
循环被重写以通过
yp
跨循环,堆分配将跨循环发生新值(我猜
yp
导致堆分配)。写
go
的有效方法是什么?在上面的例子中循环?我猜
yp
必须在
go
中作为参数传递循环,或通过
fixST
的等效方式或
CPS
转型。想不出改写的好方法
go
上面的循环以删除堆分配,并将感谢您的帮助。
最佳答案
我重写了您的函数以避免任何显式递归,并删除了一些计算偏移量的冗余操作。这编译成比您的原始函数更好的核心。
顺便说一句,Core 可能是分析编译代码以进行此类分析的更好方法。使用ghc -ddump-simpl
查看生成的核心输出,或 ghc-core
等工具
import Control.Monad.Primitive
import Control.Monad.ST
import Data.Int
import qualified Data.Vector.Unboxed.Mutable as M
import qualified Data.Vector.Unboxed as U
type MVI1 s = M.MVector (PrimState (ST s)) Int
findYP :: MVI1 s -> Int -> ST s Int
findYP fp offset = do
y0 <- M.unsafeRead fp (offset+0)
y1 <- M.unsafeRead fp (offset+2)
return $ max (y0 + 1) y1
findSnakes :: U.Vector Int32 -> MVI1 s -> Int -> Int -> (Int -> Int -> Int) -> ST s ()
findSnakes a fp k0 ct op = U.mapM_ writeAt $ U.iterateN ct (`op` 1) k0
where writeAt k = do
let offset = U.length a + k
yp <- findYP fp offset
M.unsafeWrite fp (offset + 1) (yp + k)
-- or inline findYP manually
writeAt k = do
let offset = U.length a + k
y0 <- M.unsafeRead fp (offset + 0)
y1 <- M.unsafeRead fp (offset + 2)
M.unsafeWrite fp (offset + 1) (k + max (y0 + 1) y1)
U.Vector Int32
至
findSnakes
, 只计算它的长度并且从不使用
a
再次。为什么不直接传入长度呢?
关于loops - 为 ST monad 编写高效的迭代循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17126923/
我是 C 的新手,在练习中,我必须编写以下代码部分的输出,即 3。但我不明白为什么会这样。 int main() { char st[100]="efgh"; printf ("\n%
我遇到了这个错误: java.lang.IllegalArgumentException: Removing a detached instance model.student 然后我在stackov
python 3.8.10Ubuntu 20.04 使用 st_aggrid (用于 Streamlit 的 AgGrid 的 Python 端口。) Streamlit 允许使用 st.column
这篇文章是识字的Haskell。只需放入“pad.lhs”之类的文件,ghci就可以运行它。 > {-# LANGUAGE GADTs, Rank2Types #-} > import Control
我有一个 NUCLEO-F401RE board (与 STM32F401RE ) 它在大多数情况下都运行良好。最近在这里,我按照书中的一个教程 "Mastering STM32 " 它说安装的地方
最近一两个月一直在学习Haskell,最近解决了this编码问题。额外的挑战是在没有额外空间和线性时间的情况下完成任务,我认为这不可能以纯函数的方式完成,所以自然而然地我发现了 ST monad,我认
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 4 年前。 Improve t
我已经搜索过堆栈溢出,但没有一个能真正解决我的问题。 我能够为我的库构建 .so 文件并将其加载到 jniLibs 目录中。当我运行应用程序时,我得到了这个 java.lang.Unsatisfied
我在类加载器方面遇到问题。有时有效,有时无效。 当我开始时,我已经测试了它的工作原理,但不是从 *.jar 测试的: URL url = AcAnalyzer.class.getResource(".
我正在玩http://hackage.haskell.org/packages/archive/vault/0.2.0.0/doc/html/Data-Vault-ST.html并想要编写如下所示的函
为什么 ST 被设计为禁止使用以下代码 as shown in the wikibook ?这篇文章似乎表明,如果允许的话,ST 效果会泄漏到另一个 ST 中,但我不太明白为什么。 我似乎无法运行特定
我最近开始在 Hackage 上查看核心库,并且有一个反复出现的习惯用法我不明白。这是 ST module 中的一个示例: instance Monad (ST s) where {-# IN
如果输入 url 重新启动(他们在 rtmp 流中添加新视频)然后在我的 ffmpeg 我看到这个 PTS 4294794919, next:104020298 invalid dropping st
ST monad 在 GHC 中有特殊的编译器支持吗? 最佳答案 您可以在此处查看 STRefs 的代码:http://haskell.org/ghc/docs/latest/html/librari
我确信这将是一个简单的项目,但有一个作为测试启动的项目。 创建后,它被保存为“Project2.dpr” 现在测试不再是“测试”,我想将项目名称更改为更有意义的名称。 最好的方法是什么? 仅将文件名和
我有一些代码目前使用 ST monad 进行评估。我喜欢不要把 IO 放在任何地方,因为 runST方法产生一个纯结果,并表明这样的结果是可以安全调用的(相对于 unsafePerformIO )。但
我正在努力实现 UCT Haskell 中的算法,需要大量的数据处理。无需过多讨论,它是一种模拟算法,在每个“步骤”中,根据某些统计属性选择搜索树中的叶节点,在该叶处构造一个新的子节点,以及与该叶节点
我想学习使用 ST-Monad。因此,我想为每个整数重写一些代码计算——直到一个极限——所有它的真因数的列表。结果应该是一个数组,索引“n”的条目应该是它的真除数的列表。 这是通过为每个整数“n”计算
我在 ST 中有一个计算,它通过 Data.Vector.Unboxed.Mutable 分配内存。该向量永远不会被读取或写入,也不会在 runST 之外保留任何对其的引用(据我所知)。我遇到的问
以下代码创建数组,初始化,然后返回不可变数组。 import Data.Array import Control.Monad.ST import Data.Array.ST import qualif
我是一名优秀的程序员,十分优秀!