如何将未装箱的数组添加到Haskell记录中?

时间:2012-02-11 21:41:54

标签: haskell

我想写一些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的例子,但它们主要是程序片段,所以我觉得我缺少上下文。

另外,我在哪里可以了解更多关于“种类”的内容?我知道种类是“类型类型”,但其抽象性使其难以掌握。

1 个答案:

答案 0 :(得分:4)

STUArray是一个可变数组,旨在从ST monad内部使用,以实现外部纯代码。就像STRefST monad中使用的所有其他结构一样,STUArray采用表示状态线程的附加参数。

你得到的那种错误只是告诉你错过了一个论点:在价值层面,你可能会得到一个错误“预期b但得到a -> b”告诉你错过了一个论点;在类型级别,它看起来像“预期?但得到* -> *”,其中*表示普通的“完全应用”类型(如Int)。 (您可以假装?*相同;它只是支持未装箱的类型,这是GHC特定的实现细节。)

基本上,您可以将种类视为两种形状:

  • *,代表具体类型,例如IntDouble[(Float, String)];
  • k -> l,其中kl都是种类,代表类型构造函数,例如Tree[]IOSTUArray。这样的类型构造函数采用类型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

(使用Data.Array.Unboxed.UArray

通过使用immutable array interface中的纯函数对其进行转换,可以像修改记录中的任何其他元素一样对其进行“修改”。