3

私は自分でスキームを書くを行っていて、このページの演習 4 で感銘を受けました。

どうすればいいですか?readHexここまでたどり着きましたが、がどこに行くべきかまったくわかりませんliftM。パーサーの大文字と小文字を一致させますか?

parseNumber = liftM (Number . read) $ choice [many1 digit, char '#' >> oneOf "hd" >>= a]
    where a f = case f of
        'h' -> many1 digit

<|>また、関数には適用できないと思いますよParser LispValね?

4

2 に答える 2

3

私はここまで来ましたが、 readHex がどこに行くべきかまったくわかりません。それをliftMする必要がありますか?

はい、readHex可能性が最も高いのは純粋な関数であり、liftMそれを のモナド コンテキストに持ち上げるためですParser

あなたのローカル関数が何に役立つのかよくわからないのでa、今のところそれを残して、単純に関数parseDecimalparseHex. その場合、次parseNumberのように書くことができます。

parseNumber :: Parser LispVal
parseNumber = liftM Number $ parseDecimal <|> parseHex
    where parseDecimal :: Parser Integer
          parseDecimal = liftM read $ many1 digit
          parseHex :: Parser Integer
          parseHex     = liftM readHex $ char '#' >> ... -- parse hex value

もちろん、型シグネチャは省略できますが、わかりやすくするために追加しただけです。

また、Parser LispVal 関数に <|> を適用できるとは思いませんよね?

<|>すべてに対して動作しますParser a

パーサー コンビネータに関する資料、つまりParsec User Guideを読むことをお勧めします。

于 2011-08-27T19:29:33.123 に答える
1

レイアウトを少し変更しましたが、検討中のコード例は次のとおりです。

parseNumber = 
    liftM (Number . read) $ 
        choice [many1 digit, char '#' >> oneOf "hd" >>= a]
    where
    a f =
        case f of
            'h' -> many1 digit

物事がどのように連携するべきかを知る前に、同時に多くのことをしようとしていると思います. 読み取っていた数字の種類に応じて、どうにかして areadHexを の(Number . read)代わりにパーツに移動する必要があります。read

liftMこれは、または他の派手なコンビネータを使用しない16進数のパーサーです。

parseHex :: Parser LispVal
parseHex = do
    char '#'
    char 'x'
    digits <- many1 hexDigit   -- hexDigit is defined by Parsec.
    return (Number (fst (readHex digits !! 0)))

ここで注意が必要なのは、 の結果の抽出ですreadHex

パーサーを組み合わせることができます

try parseHex <|> try parseOct <|> ... <|> parseDec

または、チューニングとインライン化、および Parsec の多くのツールに夢中になります。しかし、私は基本から始めます。

于 2011-08-27T20:22:33.097 に答える