1

私は与えられた任務に苦労しています。私はここで別のガイドに基づいてこのコードを少し書きました:スコープ外:データコンストラクター

私が抱えている問題はここのパイプです:

| x == "+" = (Sum y y',xs'') where

この問題は、3本のパイプまたは「場所」に続くパイプに関連しているようです。最後の2本のパイプを交換した場合。パッティング

x == "+"  = (Sum y y' (...))

x == "*"  = (Prod y y' (...))

エラーがそのコードに移動します。これらの2つのコードセグメントのいずれかをコメントアウトすると、すべてが正常に機能しますが、与えられた割り当てには両方が必要です。

簡単な要約:

| x == "*" = (Prod y y',xs'') where
                (y,xs') = ast xs
                (y',xs'') = ast xs'

| x == "+" = (Sum y y',xs'') where
                (y,xs') = ast xs
                (y',xs'') = ast xs'

どちらも100%単独で動作しますが、それらを組み合わせると、プログラムがコンパイルされません。

完全なコード:

import Data.Char

data AST = Leaf Int 
            | Sum AST AST 
            | Min AST 
            | Prod AST AST
            deriving Show

tokenize::String -> [String]
tokenize[] = []
tokenize('+':xs) = "+": tokenize xs
tokenize('-':xs) = "-": tokenize xs
tokenize('*':xs) = "*": tokenize xs
tokenize(x:xs) = if isDigit x then (takeWhile isDigit (x:xs)) : tokenize (dropWhile isDigit xs) else tokenize(xs)

ast :: [String] -> (AST,[String])
ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = let (y,xs') = ast xs in (Min y,xs')
    | x == "*" = (Prod y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'
    | x == "+" = (Sum y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'
4

2 に答える 2

7

問題は

ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = let (y,xs') = ast xs in (Min y,xs')
    | x == "*" = (Prod y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'
    | x == "+" = (Sum y y',xs'') where
            (y,xs') = ast xs
            (y',xs'') = ast xs'

where関数定義では、式ごとに句を 1つしか持てないということです。そのため、パーサーはパターンの式が完全であると期待whereします。x == "*"(x:xs)

問題のあるを削除するだけwhereで、where節は方程式のすべての選択肢に適用され、両方のwhere節の内容は同じです (そして、私の好みに応じて、より適切にインデントしてwhere、独自の行に属します)。最初の選択肢では、句にletも存在するバインディングを使用するため、それも削除できます。where

ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = (Min y,xs')
    | x == "*" = (Prod y y',xs'')
    | x == "+" = (Sum y y',xs'')
      where
        (y,xs') = ast xs
        (y',xs'') = ast xs'
于 2012-10-05T14:48:09.560 に答える
1

これを回避する1つの方法は、次letの代わりに使用することですwhere

ast :: [String] -> (AST,[String])
ast [] = error "Empty string"
ast (x:xs) | all isDigit x = (Leaf (read x),xs)
    | x == "-" = let (y,xs') = ast xs in (Min y,xs')
    | x == "*" = let
            (y,xs') = ast xs 
            (y',xs'') = ast xs'
            in (Prod y y',xs'')
    | x == "+" = let 
            (y,xs') = ast xs
            (y',xs'') = ast xs'
            in (Sum y y',xs'')

の中には、1つだけでなく、好きなだけ定義を含めることができますlet

whereステートメントは最後までスコープ内にありますが、でlet終了しinます。そのため、エラーメッセージが表示されました。まだにいると思っていましたwhereが、続行したいと考えていました。where条項を最後まで延期します。

この場合、それらを分離する必要はなかったので、それらを1つの場所に結合することもできますが、let一般的にこの問題には役立ちます。

于 2012-10-05T14:51:49.490 に答える