haskell / haskell/binary

Alternative instance for Get does not respect identity law in error situations

オープン
#203 コメント 0 件 リアクション 1 件 担当者 0 名 GitHub で見る
主要言語
Haskell
スター
120
フォーク
70
PR マージ指標
30日以内にマージされた PR はありません

説明

Hello,

While trying to combine `Get` parsers using `asum`, I found out that `instance Alternative Get` is not lawful: `x <|> empty` is not the same as `x` with respect to failure. `x <|> empty` errors with `"Data.Binary.Get(Alternative).empty"`, overriding the error message from `x`.

For me, an unfortunate consequence is that the implementation of `asum` leaks through: `asum [x, y] = x <|> y <|> empty` provides less helpful parse errors than `x <|> y`.

I have attached a minimal working example, also hosted on this Gist: https://gist.github.com/sugarbleat/4f30751feedf8d3e06911deae7ef4a5a, which can be run with `cabal run Main.hs`. For reference, a similar test with Parsec shows no violation of identity.

Thanks for the great work on the library, by the way!

```haskell
#!/usr/bin/env cabal
{- cabal:
build-depends: base ^>= 4.15
, bytestring ^>= 0.10.12
, binary == 0.8.9.1
-}
module Main (main) where

import Control.Applicative (Alternative (..))
import Data.Binary (Get, Word8, get)
import Data.Binary.Get (runGetOrFail)
import qualified Data.ByteString.Lazy as B
import Data.Foldable (asum)

testGet :: Show a => Get a -> B.ByteString -> IO ()
testGet p s = do
putStrLn "p"
print $ runGetOrFail p s

putStrLn "p <|> empty"
print $ runGetOrFail (p <|> empty) s

putStrLn "asum [p]"
print $ runGetOrFail (asum [p]) s

main :: IO ()
main = testGet (get :: Get Word8) B.empty

{-
Output:
p
Left ("",0,"not enough bytes")
p <|> empty
Left ("",0,"Data.Binary.Get(Alternative).empty")
asum [p]
Left ("",0,"Data.Binary.Get(Alternative).empty")
-}
```

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

Main.hs の最小例から始め、`cabal run Main.hs` で実行し、`Alternative Get` と `runGetOrFail` の結果に注目してください。`p <|> empty` が `p` の失敗を保持し、`asum [p]` がその失敗を `empty` のエラーで置き換えなくなれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
haskell
領域
backend
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
42/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。