1

Richard Bird の著書「Haskell を使用した関数型プログラミング入門」の第 2 版で演習を行っています。次のコードの最後の行で、エラーが発生します。

"Parse error in pattern (n `times` Succ m)

同じパターン (m と n を入れ替えたもの) が の定義で受け入れられたことに注意してくださいtimes。このエラーが発生するのはなぜですか?

    data Nat = Zero | Succ Nat
    deriving (Eq, Ord, Show)

    plus :: Nat -> Nat -> Nat
    m `plus` Zero = m
    m `plus` Succ n = Succ (m `plus` n)

    m `times` Zero = Zero
    m `times` Succ n = (m `times` n) `plus` m

    divide :: Nat -> Nat -> Nat
    Zero `divide` m = Zero
    (n `times` Succ m) `divide` n = Succ m
4

1 に答える 1

3

解析エラーが発生します

(n `times` Succ m) `divide` n = Succ m

定義された関数の引数はパターンでなければならないため、つまり

  • ワイルドカード_
  • 変数識別子foo
  • コンストラクター アプリケーション (アリティが要求する数のパターンに適用される値コンストラクター)
  • ラベル付きパターンF{field1 = value1, ..., fieldN = valueN}(コンストラクターFが名前付きフィールド構文を使用して定義されている場合)
  • リテラル1"foo"
  • 負のリテラル-1
  • タプルパターン、(1,2)
  • リストパターン[1,2]
  • 括弧で囲まれたパターン(pat)、パターンpatはどこですか
  • 怠惰なパターン、~patpatはパターンです

ここでの最初の引数はパターンではなく、非コンストラクター関数の関数適用です。

パターンでは値を分解できますが、通常の関数アプリケーションではできません。あなたの問題について、あなたが持っている場合

12 `divide` 4

-- そして、関数が呼び出されたときに利用できるのは値であり、取得方法ではありません -- 試行された関数定義では、指定された形式で記述できるかどうかを確認するためにコンパイラが値を因数分解する必要があります。

その行のもう 1 つの問題は、識別子nを 2 回使用していることですが、変数識別子はパターン マッチで 1 回しか使用できません。

の定義では、同じパターン ( とmn入れ替えたもの) が受け入れられたことに注意してくださいtimes

定義では

m `times` Succ n = (m `times` n) `plus` m

関数timesは、いくつかの種類の引数に対して定義されています。左側全体はパターンではありません。ここには 2 つのパターンm(すべての引数に一致し、名前にバインドする変数パターン)mSucc n(ネストされた変数 pattern を含む) がありnます。

定義の左側は、定義名 ( times) と引数の 2 つのパターンで構成されます。

の定義でdivideは、同じ構造体、定義する名前、および引数の 2 つのパターンが期待されます。

(n `times` Succ m) `divide` n = Succ m

そのため、パーサーが開き括弧に遭遇すると、括弧で囲まれたパターンを期待します。しかし、それは見つけます

     n          `times`            Succ m
pattern infix-function-application pattern

その式ツリーの最上位ノードはtimes、コンストラクターではありません。したがって、括弧の間の部分はパターンとして解析できません。

于 2012-12-13T22:58:17.117 に答える