我正在尝试使用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的工作方式有什么不同。请指教。
答案 0 :(得分:3)
您似乎只是将ST
个动作与数组本身混合在一起。修复非常简单:运行此类操作以获取其数组。这是我需要做的最小修复才能使其编译(不知道它是否“正确” - 只是它进行类型检查)。
运行ST
操作。
mStep = testMArray >>= go 0 0 where
为go
提供一个需要数组的类型,而不是ST
操作。
go :: Integer -> Int -> STArray s Int Int -> ST s Integer
定义day5Input
。 (大概你不需要向后移植这个修复程序。)
day5Input = undefined
对于您的子问题,您可以使用
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