我想写一些monte-carlo模拟。由于模拟的本质,如果我使用可变状态,我将获得更好的性能。我认为未装箱的可变阵列是可行的方法。有一堆我想跟踪的项目,所以我创建了一个记录类型来保持状态。
import Control.Monad.State
import Data.Array.ST
data Board = Board {
x :: Int
, y :: Int
,board :: STUArray (Int,Int) Int
} deriving Show
b = Board {
x = 5
,y = 5
,board = newArray ((1,1),(10,10)) 37 :: STUArray (Int,Int) Int
}
growBoard :: State Board Int
growBoard = do s <- get
let xo = x s
yo = y s in
put s{x=xo*2, y=yo*2}
return (1)
main = print $ runState growBoard b
如果我从记录中省略“board”字段,其他一切都可以正常工作。但有了它,我得到一个类型错误:
`STUArray (Int, Int) Int' is not applied to enough type arguments
Expected kind `?', but `STUArray (Int, Int) Int' has kind `* -> *'
In the type `STUArray (Int, Int) Int'
In the definition of data constructor `Board'
In the data type declaration for `Board'
我已经阅读了Array页面,我可以让STUArray示例正常工作。但是一旦我尝试将一个添加到我的状态记录中,我就会收到有关意外类型的错误。我猜我需要某种monad变换器,但我不知道从哪里开始。
如何在记录中声明未装箱的数组?我应该如何初始化它? 我看到很多未装箱的STArray的例子,但它们主要是程序片段,所以我觉得我缺少上下文。
另外,我在哪里可以了解更多关于“种类”的内容?我知道种类是“类型类型”,但其抽象性使其难以掌握。
答案 0 :(得分:4)
STUArray
是一个可变数组,旨在从ST
monad内部使用,以实现外部纯代码。就像STRef
和ST
monad中使用的所有其他结构一样,STUArray
采用表示状态线程的附加参数。
你得到的那种错误只是告诉你错过了一个论点:在价值层面,你可能会得到一个错误“预期b
但得到a -> b
”告诉你错过了一个论点;在类型级别,它看起来像“预期?
但得到* -> *
”,其中*
表示普通的“完全应用”类型(如Int
)。 (您可以假装?
与*
相同;它只是支持未装箱的类型,这是GHC特定的实现细节。)
基本上,您可以将种类视为两种形状:
*
,代表具体类型,例如Int
,Double
或[(Float, String)]
; k -> l
,其中k
和l
都是种类,代表类型构造函数,例如Tree
,[]
, IO
和STUArray
。这样的类型构造函数采用类型k
,并返回类型l
。如果您想使用ST
数组,则需要向Board
添加类型参数:
data Board s = Board {
x :: Int
, y :: Int
,board :: STUArray s (Int,Int) Int
} deriving Show
并使用StateT (Board s) (ST s)
作为您的monad,而不只是State Board
。
但是,我没有看到任何理由在这里使用ST
或可变结构,我建议使用一个简单的不可变数组,并以与其他状态相同的方式对其进行变更,State
monad:
data Board = Board {
x :: Int
, y :: Int
,board :: UArray (Int,Int) Int
} deriving Show
通过使用immutable array interface中的纯函数对其进行转换,可以像修改记录中的任何其他元素一样对其进行“修改”。