基本的なことを学んだ後、私はBittorrentクライアントを使い始めたHaskellで「現実世界のアプリケーション」を試したかったのです。このblog postの説明に続いて、私はAttoparsec parser combinatorライブラリを使用しませんでした。代わりにHuttons bookに続いて、私はParser Combinatorsを書き始めました。上記Haskellアプリケーションのデバッグ
module Main where
import System.Environment (getArgs)
import qualified Data.Map as Map
import Control.Monad (liftM, ap)
import Data.Char (isDigit, isAlpha, isAlphaNum, ord)
import Data.List(foldl')
main :: IO()
main = do
[fileName] <- getArgs
contents <- readFile fileName
download . parse $ contents
parse :: String -> Maybe BenValue
parse s = case runParser value s of
[] -> Nothing
[(p, _)] -> Just p
download :: Maybe BenValue -> IO()
download (Just p) = print p
download _ = print "Oh!! Man!!"
data BenValue = BenString String
| BenNumber Integer
| BenList [BenValue]
| BenDict (Map.Map String BenValue)
deriving(Show, Eq)
-- From Hutton, this follows: a Parser is a function
-- that takes a string and returns a list of results
-- each containing a pair : a result of type a and
-- an output string. (the string is the unconsumed part of the input).
newtype Parser a = Parser (String -> [(a, String)])
-- Unit takes a value and returns a Parser (a function)
unit :: a -> Parser a
unit v = Parser (\inp -> [(v, inp)])
failure :: Parser a
failure = Parser (\inp -> [])
one :: Parser Char
one = Parser $ \inp -> case inp of
[] -> []
(x: xs) -> [(x, xs)]
runParser :: Parser a -> String -> [(a, String)]
runParser (Parser p) inp = p inp
bind :: Parser a -> (a -> Parser b) -> Parser b
bind (Parser p) f = Parser $ \inp -> case p inp of
[] -> []
[(v, out)] -> runParser (f v) out
instance Monad Parser where
return = unit
p >>= f = bind p f
instance Applicative Parser where
pure = unit
(<*>) = ap
instance Functor Parser where
fmap = liftM
choice :: Parser a -> Parser a -> Parser a
choice p q = Parser $ \inp -> case runParser p inp of
[] -> runParser q inp
x -> x
satisfies :: (Char -> Bool) -> Parser Char
satisfies p = do
x <- one
if p x
then unit x
else failure
digit :: Parser Char
digit = satisfies isDigit
letter :: Parser Char
letter = satisfies isAlpha
alphanum :: Parser Char
alphanum = satisfies isAlphaNum
char :: Char -> Parser Char
char x = satisfies (== x)
many :: Parser a -> Parser [a]
many p = choice (many1 p) (unit [])
many1 :: Parser a -> Parser [a]
many1 p = do
v <- p
vs <- many p
unit (v:vs)
peek :: Parser Char
peek = Parser $ \inp -> case inp of
[] -> []
[email protected](x:xs) -> [(x, v)]
taken :: Int -> Parser [Char]
taken n = do
if n > 0
then do
v <- one
vs <- taken (n-1)
unit (v:vs)
else unit []
takeWhile1 :: (Char -> Bool) -> Parser [Char]
takeWhile1 pred = do
v <- peek
if pred v
then do
one
vs <- takeWhile1 pred
unit (v:vs)
else unit []
decimal :: Integral a => Parser a
decimal = foldl' step 0 `fmap` takeWhile1 isDigit
where step a c = a * 10 + fromIntegral (ord c - 48)
string :: Parser BenValue
string = do
n <- decimal
char ':'
BenString <$> taken n
signed :: Num a => Parser a -> Parser a
signed p = (negate <$> (char '-' *> p))
`choice` (char '+' *> p)
`choice` p
number :: Parser BenValue
number = BenNumber <$> (char 'i' *> (signed decimal) <* char 'e')
list :: Parser BenValue
list = BenList <$> (char 'l' *> (many value) <* char 'e')
dict :: Parser BenValue
dict = do
char 'd'
pair <- many ((,) <$> string <*> value)
char 'e'
let pair' = (\(BenString s, v) -> (s,v)) <$> pair
let map' = Map.fromList pair'
unit $ BenDict map'
value = string `choice` number `choice` list `choice` dict
3つの源the blogのソースコードから理解コード読み取り/の混合である、the library:これは私は(解析段階、先に長い旅のまま)、これまで持っているコードであります、およびthe book。 download
関数はパーサーから得られた "解析木"を出力するだけです。パーサーが機能したら、download
関数を入力してテストしてください。
- パーサーは、いくつかのトレントファイルで動作していません。 :(そこ間違いなく、私が間違って参照からのコードを使用している可能性があることのチャンスです。そして、明らかに何があるかどうかを知りたい。
- それは「おもちゃ」の例にもcombinatorrent
- から選んだテストファイル上で動作します私はDebianの/ Ubuntuのなどのような実世界の急流を選択すると、これは失敗します。
- 私はデバッグし、何が起こっているか見てみたい、GHCiの持つデバッグはまっすぐ前方にいないようです、私が言及した
:trace
/:history
スタイルのデバッグを試してみましたこのdocumentでは、非常に原始的です:-)。 - エキスパートには私の質問があります。「どのようにデバッグするのですか?」 :-)
- これをデバッグする方法にどのようなヒントがありますか本当に感謝します。
ありがとうございます。
私はこれは質問から少し外れていると思いますが、バイナリデータを使って作業している場合は、 'readFile'と' String'を使用するのがベストのアイデアではないかもしれません。代わりに['ByteString'](https://hackage.haskell.org/package/bytestring-0.10.8.1/docs/Data-ByteString.html)とそれに対応するすべての関数(これにはバージョンの['readFile'](http://hackage.haskell.org/package/bytestring-0.10.8.1/docs/Data-ByteString-Char8.html#v:readFile)も参照してください。 – Alec
また、ポイント2で指定されたファイルでコードを試してみると、 'hGetContents:無効な引数(無効なバイトシーケンス)'(これはおそらく私の最初のコメントに関連しています)を与えてくれます。あなたはどんな出力を見ていますか? – Alec
私はこれをWindowsマシンで試してみました。それが問題であれば訴訟を起こさず、別のOSでこれを試してみましょう。ありがとう。 – user3169543