2017-12-05 4 views
1

私はHaskellを使用して今年のAdvent of Codeを解決しようとしていますが、5日目に問題に遭遇しました。ジャンプのリストの指示にジャンプし、命令セットを終了する。私はIArrayでこれを正しく実装しましたが、代わりにMArrayで再実装しようとしているので、STモナドの怖い世界に私を投げ込んでいます。ここでSTArrayのインデックスで型エラーが発生する

は私の正しく動作するコードです:

私は再作成して STArrayを使用しようとし
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 

:私はエラーを取得するしかし

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とどのように違うのか分かりません。お知らせ下さい。

+2

「testMArray」とは何ですか? 'testMArray >> = go 0 0'などが必要です。 –

+0

@DanielWagner 'testMArray :: ST(STArray s Int Int)'です。私は編集します。 –

+1

@AdamSmith興味がある場合は、私も同じことをしましたが、可変ベクトルを使用しました:https://github.com/ZedPea/advent-of-code/blob/master/day05-2.hs – Zpalmtree

答えて

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 
    

、あなたが動的に境界を取得するために

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

を使用することができます。 So:

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 
+0

はい、それはそうだと思います。だから、 'testMArray'はステートフルな配列ではなく、ただ一つのアクションを生成するアクションですか?最近、私はハスケルを理解するつもりで、私の神性は壮大になるでしょう;) –

+2

@AdamSmith Correct! –

+1

これを読んで、私はなぜ 'MA。getBounds'は、モナドの内側ではなくモナドの内側にあるペアを返します。 'MArray'は、MA.getBounds'のモナド性を正当化するために、サイズ変更をサポートする配列型のいくつかのインスタンスを持っていますか?可能であれば、実際には必要以上に一般的です(?)。 – chi

関連する問題