2012-04-26 35 views
3

このコード部分は、2つ以上の数値(主な関数が省略されている)を読み込み、合計を与えるために "+"を読み込む必要があります。私は後で私は乗算とそのような他の操作を行うので、競合が使用されます。*** Exception:Prelude.read:Haskellで構文解析をしない - 構文解析、式および再帰

data Expression = Number Rational 
       | Add (Expression)(Expression) 
       deriving(Show,Eq) 

solve :: Expression -> Expression 
solve (Add (Number x) (Number y)) = Number (x + y) 

parse :: [String] -> [Expression] -> Double 
parse ("+":s)(a:b:xs) = parse s (solve (Add a b):xs) 
parse [] (answer:xs) = fromRational (toRational (read (show answer)::Float)) 
parse (x:xs) (y) = parse (xs) ((Number (toRational (read x::Float))):y) 

(第2)の誤差が

*Main> parse ["1","2","+"] [Number 3] 

*** Exception: Prelude.read: no parse 

を処理することができませんでしparse関数である私は、このソリューションのためにData.Ratioページ上やウェブ上で見てきましたが、それを発見していませんいくつかの助けに感謝します。型シグネチャごとに、ab既にExpression Sであるためおかげで、

CSJC

+0

あなたの2番目のエラーはすでに私の答えで扱われています:) –

+0

はい、あなたはすでに私がそれを入力していたようなものを先取りしたようです! – CSJC

答えて

2

最初の方程式、

parse ("+":s)(a:b:xs) = parse (s)((solve (Add (Number a) (Number b))):xs) 

parse ("+":s)(a:b:xs) = parse (s)((solve (Add a b)):xs) 

であるべきです。

または、第二及び第三の方程式に沿って、

parse :: [String] -> [Rational] -> Double 

にタイプを変更し、そこにコードを固定する

parse ("+":s)(a:b:xs) = parse s ((a + b):xs) 

2つの方法(第一の方程式を変更しますより問題の多い部分でした):

-- Complete solve to handle all cases 
solve :: Expression -> Expression 
solve [email protected](Number _) = expr 
solve (Add (Number x) (Number y)) = Number (x + y) 
solve (Add x y) = solve (Add (solve x) (solve y)) 

-- Convert an Expression to Double 
toDouble :: Expression -> Double 
toDouble (Number x) = fromRational x 
toDouble e = toDouble (solve e) 

-- parse using a stack of `Expression`s 
parse :: [String] -> [Expression] -> Double 
parse ("+":s) (a:b:xs) = parse s ((solve (Add a b)):xs) 
parse [] (answer:_) = toDouble answer 
parse (x:xs) ys = parse xs (Number (toRational (read x :: Double)) : ys) 
parse _ _ = 0 

-- parse using a stack of `Rational`s 
parseR :: [String] -> [Rational] -> Double 
parseR ("+":s) (a:b:xs) = parseR s (a+b : xs) 
parseR [] (answer:xs) = fromRational answer 
parseR (x:xs) y = parseR xs ((toRational (read x::Double)):y) 
parseR _ _ = 0 

最後にDoubleが生成されるので、後者はかなり気をつけます。スタックにはRationalを使用する実際のポイントはありません。 parseのためのあなたのコードで

は、第三式はNumberコンストラクタ経由RationalExpressionへの転換を残し、それ以外は大丈夫です。第2の式は、しかし、問題の異なるタイプを含む:

parse [] (answer:xs) = fromRational (toRational (read (show answer)::Float)) 

answerExpression又はRationalのいずれかである場合、show answerFloatとして解析することができないので、によって例示されるようなことは、ランタイムエラーにつながりますあなたの編集:

(第2)の誤差は、解析機能を

*Main> parse ["1","2","+"] [Number 3] 
*** Exception: Prelude.read: no parse 
を処理することができません

第2式が使用される時点で、readFloatとして解析できるStringされていない、スタック上の最初の要素(answer)はNumber (3 % 1)であり、そしてshow (Number (3 % 1))"Number (3 % 1)"あります。

+0

これを明確にしていただきありがとうございます。 – CSJC

+0

'solve(Add(Number x)(Number y))= Number(x + y)'は 'solve(Add x y)= Number(x + y)'になりますか? – CSJC

+0

いいえ、 'xy'を追加すると' x'と 'y'は' Expression'sですが、 'Number'は' Rational'引数をとり、 '(+)'は 'Expression'sには定義されていません。 'solve'は実装されている限り正しいです(もちろん、不完全です)。 –

関連する問題