Arrays 在星空列表上绘制星空运行图?
我有一个函数,它从树中递归创建一个扁平的矩阵列表,这些矩阵必须是可变的,因为它们的元素在创建过程中经常更新。到目前为止,我已经提出了一个递归解决方案,其特征是:Arrays 在星空列表上绘制星空运行图?,arrays,haskell,state,higher-rank-types,Arrays,Haskell,State,Higher Rank Types,我有一个函数,它从树中递归创建一个扁平的矩阵列表,这些矩阵必须是可变的,因为它们的元素在创建过程中经常更新。到目前为止,我已经提出了一个递归解决方案,其特征是: doAll :: .. -> [ST s (STArray s (Int, Int) Int)] 我不直接返回[UArray(Int,Int)Int]的原因是doAll被递归调用,修改列表中矩阵的元素并附加新矩阵。我不想不必要地冻结和解冻矩阵 到目前为止还不错。我可以检查ghci中的n-th矩阵(类型数组(Int,Int)Int
doAll :: .. -> [ST s (STArray s (Int, Int) Int)]
我不直接返回[UArray(Int,Int)Int]
的原因是doAll
被递归调用,修改列表中矩阵的元素并附加新矩阵。我不想不必要地冻结和解冻矩阵
到目前为止还不错。我可以检查ghci中的n
-th矩阵(类型数组(Int,Int)Int
)
runSTArray (matrices !! 0)
runSTArray (matrices !! 1)
事实上,我得到了正确的算法结果。但是,我没有找到将runSTUArray
映射到doAll
返回的列表的方法:
map (runSTArray) matrices
Couldn't match expected type `forall s. ST s (STArray s i0 e0)'
with actual type `ST s0 (STArray s0 (Int, Int) Int)'
如果我尝试对列表递归求值,或者尝试求值封装在函数中的单个元素,同样的问题也会发生
有人能解释一下发生了什么事(我真的不明白对所有
关键字的含义)以及我如何评估列表中的数组吗?您刚刚克服了类型系统的限制
runSTArray具有较高的排名类型。必须向其传递状态类型变量唯一的ST操作。然而,在Haskell中,通常不可能在列表中包含这样的值
整件事都是一个聪明的计划,以确保你在ST动作中产生的价值不能从那里逃脱。也就是说,看起来你的设计不知怎么被打破了
一个建议是:你不能在另一个ST动作中处理这些值,比如
sequence [ ... your ST s (STArray s x) ...] >>= processing
where
processing :: [STArray s x] -> ST s (your results)
这是使ST
安全的类型技巧的不幸后果。首先,您需要知道ST是如何工作的。从ST
monad转换为纯代码的唯一方法是使用runST
函数,或是基于它构建的其他函数,如runSTArray
。这些都是所有s.
的形式。这意味着,为了从STArray构造数组,编译器必须能够确定它可以用它喜欢的任何类型替换s
type变量runST
现在考虑函数<代码> MAP:(A->B)-> [A] -> [B] < /代码>。这表明列表中的每个元素必须具有完全相同的类型(
a
),因此也必须具有相同的s
。但是这个额外的约束违反了runSTArray
的类型,它声明编译器必须能够自由地用其他值替换s
您可以通过定义一个新函数来解决此问题,该函数首先冻结ST monad中的数组,然后运行生成的ST操作:
runSTArrays :: Ix ix => (forall s. [ST s (STArray s ix a)]) -> [Array ix a]
runSTArrays arrayList = runST $ (sequence arrayList >>= mapM freeze)
注意,
forall
需要RankNTypes
扩展名。谢谢您的解释,这很有意义。不过,我必须删除您的runstarlays
中的runST
,稍后再单独调用它ghc
无法推断上下文,也不接受显式类型注释。对此表示抱歉;我已将适当的类型注释添加到此代码中。GHC不推断更高级的类型注释(forall),因此需要手动提供。程序是否有占位符用于“更新数组内容的某些功能”?@misterbee-否,序列
用于转换ST s(STArray s ix a)列表
将操作转换为单个ST操作,生成星号列表。如果需要更新数组内容的函数(我不相信它们是用于OP的),它们将进入传递给mapM的函数,例如mapM(\array->updateArray array>>冻结数组)
@John L,谢谢。我问这个问题是因为我有一个类似于OP的例子,我想以“mdo”的方式有效地更新一对星号中的许多值,在这种情况下,后面的更改取决于前面的更改(数组基本上代表搜索算法的状态空间),我想知道我的设计在哪种意义上会被破坏(我并不怀疑这一点,我对哈斯克尔来说是个新手)。你对如何管理不断增长的可变矩阵列表以供传递和评估有什么建议吗?@bbtrb-也许这不是设计本身,而是希望处理一系列ST…
事物。基本上,这些矩阵都是可变数据,这意味着你不能(或者至少不应该)在ST或IO操作之外使用它们。正如John L告诉你的,这是由runST*函数家族的类型强制执行的。freeze
只是告诉Haskell系统,从今以后,你希望将矩阵(或任何东西)作为只读值处理,然后它允许转义(的副本)在ST操作中构造的值。