HaskellでParsecが動かないので質問です


Haskell勉強中の初心者です
Parsecを使った構文解析を勉強中なのですが
(letter <|> digit)
という箇所で次のエラーが出てきます

No instance for (Text.Parsec.Prim.Stream s0 m0 Char)
arising from a use of `digit'
Possible fix:
add an instance declaration for
(Text.Parsec.Prim.Stream s0 m0 Char)
In the second argument of `(<|>)', namely `digit'
In the first argument of `many', namely `(letter <|> digit)'
In a stmt of a 'do' expression: cs <- many (letter <|> digit)
かなり初心者な質問なのでしょうがお答えいただければ幸いです

http://www.f13g.com/%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0/Haskell/Parsec/

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2012/01/08 23:23:29
  • 終了:2012/01/09 07:37:23

ベストアンサー

id:ruicc No.1

ruicc回答回数2ベストアンサー獲得回数12012/01/09 00:35:20

ポイント300pt

リンク先のコードを試してみたところ、問題なく実行出来ました。
恐らくそのコードを変更しつつ試していたのだと思いますが、原因は型推論の失敗であると思われます。


以下のコードで似たようなエラーが確認出来ました。
リンク先のコードに最後4行加えたものです。

import Text.ParserCombinators.Parsec

run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x

word = do c <-letter
          cs<-many (letter <|> digit)
          return (c:cs)

file = do f<-fileUnit
          f2<-file
          return (f++f2)
       <|> return ""
    where
      fileUnit = word
                 <|> do c<-oneOf "-_./~"
                        return [c]

host = do u<-hostUnit
          h<-host
          return (u++h)
       <|> return ""
    where
      hostUnit = word
                 <|> do c<-oneOf "-_."
                        return [c]

uri = do string "http://"
         h <- host
         f <- file
         return (h,f)

main = run uri "http://example.com/hoge"

--digitOrLetter :: Parser Char -- ここのコメントアウトを外すと動く
digitOrLetter = digit <|> letter

最後から2行目のコメントを外すときちんと型推論が通り、動く様になります。
最後の行で定義したdigitOrLetterは「定義したのみ」であり、実際には使っていません。しかしその正に使っていないがために自身の定義から型を推論するしかなく、結果的に情報が足りず型推論が失敗してしまっているようです。なので、例えばmainを

main = print $ parse digitOrLetter "" "some input string" 

このように変更し、digitOrLetterを使う様にすると、digitOrLetterの型は書かずともコンパイラが推論してくれます。

パーサコンビネータは型が自明な小さなパーサを大量に書くために、個々の型を省略することが多いのですが、このようなケースもあるのですね。

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません