IT練習ノート

IT関連で調べたこと(実際は嵌ったこと)を書いています。

haskellのlookAheadの練習

BinaryパッケージにlookAhead関数があります。

https://hackage.haskell.org/package/binary-0.5.0.2/docs/src/Data-Binary-Get.html#lookAhead

Prelude> :t Data.Binary.Get.lookAhead
Data.Binary.Get.lookAhead
  :: Data.Binary.Get.Get a -> Data.Binary.Get.Get a

型をみると、GetモナドをとりGetモナドを返す関数で、使い方がイメージできませんでした。

ソースを確認すると、getしてputするという地道な(!)ことをしています。

-- | Run @ga@, but return without consuming its input.
-- Fails if @ga@ fails.
lookAhead :: Get a -> Get a
lookAhead ga = do
    s <- get
    a <- ga
    put s
    return a

これをみるとgaという関数を実行しているので、lookAhead関数に関数を渡せば良いことがわかります。

なので、lookAhead関数にGetモナドを渡せばよいと。

Prelude> 
Prelude> :t Data.Binary.Get.lookAhead Data.Binary.Get.getWord8
Data.Binary.Get.lookAhead Data.Binary.Get.getWord8
  :: Data.Binary.Get.Get GHC.Word.Word8
Prelude> 

準備としてByteStringの作成

Prelude> :t Data.ByteString.Lazy.Char8.pack
Data.ByteString.Lazy.Char8.pack
  :: [Char] -> Data.ByteString.Lazy.Internal.ByteString
Prelude> Data.ByteString.Lazy.Char8.pack "123acdefg"
"123acdefg"
Prelude> 

1バイト目を取得

Prelude> Data.Binary.Get.runGet (Data.Binary.Get.getWord8) (Data.ByteString.Lazy.Char8.pack "123acdefg")
49
Prelude> 

1バイト目を先読みで取得

Prelude> Data.Binary.Get.runGet (Data.Binary.Get.lookAhead Data.Binary.Get.getWord8) (Data.ByteString.Lazy.Char8.pack "123acdefg")
49
Prelude> 

1バイト分だと先読みしているかがわかりにくいので、バイト読み込みを2回してみます。

2バイト目を取得

Prelude> Data.Binary.Get.runGet (Data.Binary.Get.getWord8 >> Data.Binary.Get.getWord8) (Data.ByteString.Lazy.Char8.pack "123acdefg")
50
Prelude> 

1バイト目を先読みして、もう一度1バイト分を読む

Prelude> Data.Binary.Get.runGet (Data.Binary.Get.lookAhead Data.Binary.Get.getWord8 >> Data.Binary.Get.getWord8) (Data.ByteString.Lazy.Char8.pack "123acdefg")
49
Prelude> 

確かに先読みしていることが確認できました。