0

Read ComplexInt のインスタンスに取り組んでいます。

与えられたものは次のとおりです。

data ComplexInt = ComplexInt Int Int
deriving (Show)

module Parser (Parser,parser,runParser,satisfy,char,string,many,many1,(+++)) where

import Data.Char
import Control.Monad
import Control.Monad.State

type Parser = StateT String []

runParser :: Parser a -> String -> [(a,String)]
runParser = runStateT

parser :: (String -> [(a,String)]) -> Parser a
parser = StateT

satisfy :: (Char -> Bool) -> Parser Char
satisfy f = parser $ \s -> case s of
    [] -> []
    a:as -> [(a,as) | f a]

char :: Char -> Parser Char
char = satisfy . (==)

alpha,digit :: Parser Char
alpha = satisfy isAlpha
digit = satisfy isDigit

string :: String -> Parser String
string = mapM char

infixr 5 +++
(+++) :: Parser a -> Parser a -> Parser a
(+++) = mplus

many, many1 :: Parser a -> Parser [a]
many p = return [] +++ many1 p
many1 p = liftM2 (:) p (many p)

与えられた演習は次のとおりです。

"Use Parser to implement Read ComplexInt, where you can accept either the simple integer 
syntax "12" for ComplexInt 12 0 or "(1,2)" for ComplexInt 1 2, and illustrate that read 
works as expected (when its return type is specialized appropriately) on these examples. 
Don't worry (yet) about the possibility of minus signs in the specification of natural 
numbers."

これが私の試みです:

data ComplexInt = ComplexInt Int Int
    deriving (Show)

instance Read ComplexInt where
    readsPrec _ = runParser parseComplexInt

parseComplexInt :: Parser ComplexInt
parseComplexInt = do
    statestring <- getContents
    case statestring of
        if '(' `elem` statestring 
            then do process1 statestring
            else do process2 statestring
    where
    process1 ststr = do
        number <- read(dropWhile (not(isDigit)) ststr) :: Int
        return ComplexInt number 0
    process2 ststr = do
        numbers <- dropWhile (not(isDigit)) ststr
        number1 <- read(takeWhile (not(isSpace)) numbers) :: Int
        number2 <- read(dropWhile (not(isSpace)) numbers) :: Int
        return ComplexInt number1 number2

これが私のエラーです(これを整理するとさらに多くのエラーが発生すると確信しているため、現在のエラーですが、一度に1ステップずつ実行します):

Parse error in pattern: if ')' `elem` statestring then
                            do { process1 statestring }
                        else
                            do { process2 statestring }

この質問で使用されている構造に基づいて、if-then-else ステートメントの構造を作成しました

明らかなエラーが発生した場合は、if-then-else ブロックと一般的なコードのヘルプをいただければ幸いです。

4

2 に答える 2

6

解析エラー周辺のコードを見てみましょう。

case statestring of
    if '(' `elem` statestring 
        then do process1 statestring
        else do process2 statestring

それはどのようにcase機能するかではありません。次のように使用することになっています。

case statestring of
    "foo"  ->  -- code for when statestring == "foo"
    'b':xs ->  -- code for when statestring begins with 'b'
    _      ->  -- code for none of the above

を実際に使用するわけではないのでcasecase行を完全に削除してください。

(また、これらの後にはそれぞれ 1 つのステートメントしか続かないため、 と の後のsdoは不要です。)thenelse

于 2013-11-09T21:59:24.347 に答える
1

操作する関数がいくつか与えられたと述べましたが、それらを使用しませんでした! たぶん私は誤解しました。あなたのコードはごちゃごちゃしているようで、あなたが望むものを達成していないようです。getContentstype を持つへの呼び出しがありますIO Stringが、その関数は io モナドではなく、パーサー モナドにあるはずです。

実際にそれらを使用したい場合は、次の方法があります。

readAsTuple :: Parser ComplexInt
readAsTuple = do
  _ <- char '('          
  x <- many digit
  _ <- char ','
  y <- many digit
  _ <- char ')'
  return $ ComplexInt (read x) (read y)

readAsNum :: Parser ComplexInt
readAsNum = do
  x <- many digit
  return $ ComplexInt (read x) 0

instance Read ComplexInt where
  readsPrec _ = runParser (readAsTuple +++ readAsNum)

" 42"(スペースを含むもの)のような文字列は失敗するため、これはかなり基本的なものです。

使用法:

> read "12" :: ComplexInt 
ComplexInt 12 0
> read "(12,1)" :: ComplexInt
ComplexInt 12 1

Read型クラスには ; と呼ばれるメソッドがありreadsPrecます。このメソッドを定義するだけで、型の読み取りインスタンスを完全に定義でき、関数がread自動的に提供されます。

とはreadsPrec?

readsPrec :: Int -> String -> [(a, String)]. 最初のパラメーターは優先コンテキストです。これは、最後に解析されたものの優先順位と考えることができます。これは 0 から 11 の範囲です。デフォルトは 0 です。このような単純な解析では、それを使用することさえありません。より複雑な (つまり、再帰的な) データ型の場合、優先コンテキストを変更すると、解析が変更される場合があります。

2 番目のパラメーターは入力文字列です。

出力タイプは可能な解析であり、解析が終了したままの文字列です。例えば:

>runStateT (char 'h') "hello world"
[('h',"ello world")]

解析は決定論的ではないことに注意してください。一致するすべての解析が返されます。

>runStateT (many1 (char 'a')) "aa"
[("a","a"),("aa","")]

返されるリストが、2 番目の値が空の文字列であるシングルトン リストである場合、解析は成功したと見なされます。すなわち:[(x, "")]一部のx. 空のリスト、または残りの文字列のいずれかが空の文字列ではないリストはエラーno parseを返し、複数の値を持つリストはエラーを返しますambiguous parse

于 2013-11-10T12:07:23.627 に答える