STArray索引给出了类型错误

时间:2017-12-05 22:02:11

标签: haskell

我正在尝试使用Haskell解决今年的Advent of Code问题,并在第5天遇到问题,要求我们跳转跳转列表中的说明并计算退出前需要执行的步数指令系统。我用IArray s正确实现了这个,但是反复重新初始化这个巨大的数组似乎是浪费,所以我试图用MArray重新实现,这让我陷入困境ST monad的可怕世界。

这是我正确使用的代码:

import qualified Data.Array as A

-- sample input
day5Input :: [Int]
day5Input = [0, -1, 1032] ++ replicate 1030 [1]  -- to fill the array

day5Array :: A.Array Int Int
day5Array = A.listArray (0, 1032) day5Input

p1Day5Result :: Integer
p1Day5Result = go 0 0 day5Array where
  go :: Integer -> Int -> A.Array Int Int -> Integer
  go c i a | i > ubound || i < lbound = c
           | otherwise                = let n = a A.! i
                                            i' = i+n
                                            n' = n+1
                                            a' = a A.// [(i, n')]
                                        in  go (c+1) i' a'
  (lbound, ubound) = A.bounds day5Array

我试图使用STArray重新创建:

import Data.Array.MArray as MA
import Data.Array.ST (STArray, runSTArray)
import Control.Monad.ST

-- sample input
day5Input :: [Int]
day5Input = [0, -1, 1032] ++ replicate 1030 [1]  -- to fill the array

testMArray :: ST s (STArray s Int Int)
testMArray = MA.newListArray (0, 1032) day5Input

mStep :: ST s Integer
mStep = go 0 0 testMArray where
  go :: Integer -> Int -> ST s (STArray s Int Int) -> ST s Integer
  go c i arr | i > ubound || i < lbound = return c
             | otherwise                = do
                     n <- MA.readArray arr i
                     let i' = i+n
                         n' = n+1
                     MA.writeArray arr i n'
                     go (c+1) i' arr
  (lbound, ubound) = (0, 1032)  -- sub-question, how do I query for this
                                -- like I did with A.bounds above?

然而我收到错误:

day5.hs:1091:44: error:
    * Couldn't match expected type `s1' with actual type `Int'
      `s1' is a rigid type variable bound by
        the type signature for:
          go :: forall s1.
                Integer -> Int -> ST s1 (STArray s1 Int Int) -> ST s1 Integer

我没有看到我的代码与this example code的工作方式有什么不同。请指教。

1 个答案:

答案 0 :(得分:3)

您似乎只是将ST个动作与数组本身混合在一起。修复非常简单:运行此类操作以获取其数组。这是我需要做的最小修复才能使其编译(不知道它是否“正确” - 只是它进行类型检查)。

  1. 运行ST操作。

    mStep = testMArray >>= go 0 0 where
    
  2. go提供一个需要数组的类型,而不是ST操作。

    go :: Integer -> Int -> STArray s Int Int -> ST s Integer
    
  3. 定义day5Input。 (大概你不需要向后移植这个修复程序。)

    day5Input = undefined
    
  4. 对于您的子问题,您可以使用

    getBounds :: (Ix i, MArray a e m) => a i e -> m (i, i)
    

    动态获取边界。所以:

    mStep = do
        arr <- testMArray
        (lbound, ubound) <- MA.getBounds arr
        go lbound ubound 0 0 arr
        where
        go :: Int -> Int -> Integer -> Int -> STArray s Int Int -> ST s Integer
        go lbound ubound c i arr | -- same as before
            -- until the very last line
            go lbound ubound (c+1) i' arr