5

私はこのコードを書きました:

addNums key num = add [] key num
    where add res a:as b:bs
        | a == [] = res
        | otherwise = add res:(a+b) as bs

3行目で通訳は次のように述べています。

解析エラー(インデントが正しくない可能性があります)

コードでもインデントでも、何か問題は見つかりませんでした。タブごとに4つのスペースを配置します。

注釈:

これでもコンパイルされません:

addNums key num = add [] key num
    where add res a:as b:bs
            | a == [] = res
            | otherwise = add res:(a+b) as bs

2行目:

パターンの解析エラー:追加

4

3 に答える 3

10

Haskellの主なインデンドルールは、別の行で定義を継続したい場合は、定義しているものよりもさらにインデントする必要があるということです。この場合、add関数のガードはインデントされていないので、コンパイラーはそれについて不平を言っています。

コード内の他のエラーを無視すると、インデントは次のようになります。

addNums key num = add [] key num
    where add res a:as b:bs
            | a == [] = res
            | otherwise = add res:(a+b) as bs

また、インデントの正確な量は重要ではなく、定義されているものに対する継続行のインデントのみが重要であることに注意してください。

コードのもう1つの構文上の問題は、Haskellの優先順位規則を誤解しているように見えることです。Haskellでは、関数適用はどの演算子よりも緊密にバインドされるため、あなたが意味している間、add res a:as b:bsとして解析されます。(add res a):(as b):bsadd res (a:as) (b:bs)

最後の問題はタイプエラーです。(:)演算子のタイプは、要素リストを受け取り、リストを生成するa -> [a] -> [a]ことを意味します。あなたのコードでは、リストと要素であるように、これが逆になっているように見えます。Haskellにはリストの最後に単一の要素を追加する演算子がないため、代わりにリスト連結演算子を使用する必要があります。res:(a+b)resa+b(++) :: [a] -> [a] -> [a]res ++ [a+b]

また、要素 aをガード内のリスト と比較しています。[]これはおそらくあなたが意図したものでは(a:as)なく、リストが空の場合、パターンは一致しません。これに対する最も簡単な解決策は、ガードの代わりに別のパターンを追加することです。

これらすべてをまとめると、このコードは意図したとおりに機能するはずです。

addNums key num = add [] key num
    where add res [] _ = res
          add res (a:as) (b:bs) = add (res ++ [a+b]) as bs

PSリストの最後に繰り返し追加するのはあまり効率的ではありません。実際、それはO(n 2)です。代わりに前に追加し、完了したらリストを逆にすることをお勧めします。これはO(n)です。


参照:

于 2011-08-24T15:38:43.713 に答える
4

少なくとも最初の定義(addあなたの場合)まで、where句のパターンガードをインデントする必要があるため、インデントエラーが発生します。

その上、タイプエラーのためにコードはまだコンパイルされません。つまりa、リストではないので、a == []タイプチェックはしません。さらに、(リストに一致するパターンと追加する引数のために)より多くの括弧が必要です。

あなたは多分このようなことを意味しましたか?

addNums key num = add [] key num
    where add res (a:as) (b:bs)
            | as == [] = res
            | otherwise = add (res ++ [a+b]) as bs

編集: ところで、私はあなたが本当に次のことをしたいと思うと思います:

addNums key num = add [] key num
    where add res (a:as) (b:bs)
           | as == [] = res ++ [a+b]
           | otherwise = add (res ++ [a+b]) as bs

その場合は、次のように書くこともできますaddNums = zipWith (+)(ただし、2番目のリストが最初のリストより短い場合は、パターンマッチの例外がスローされないため、少し異なります)。

于 2011-08-24T15:48:59.783 に答える
2

2番目の問題は空白の問題ではありません。複雑なパターンを括弧で囲む必要があるため、次のa:asようb:bsに記述します。add res (a:as) (b:bs)

別の言い方をすれば、空白についてのポイントを言い換えると、where句での空白の見方は、トップレベルでの見方です。あなたは書くでしょう:

addNums1 key num = add [] key num

add res (a:as) (b:bs)
  | as == [] = res
  | otherwise = add (res ++ [a+b]) as bs

したがって、インデントを追加すると、次のようになります。

 addNums2 key num = add [] key num
   where 
   add res (a:as) (b:bs)
     | as == [] = res
     | otherwise = add (res ++ [a+b]) as bs

ただし、where句のインデントを解除することはできないため、左マージンになります。(私はそれを同等のものに変更します)

addNums key num = add [] key num
  where   
  add res a:as b:bs
| a == [] = res
| otherwise = add res:(a+b) as bs

警備員が左側にいるのでadd; ここでは、実際には左マージンになります。従属定義を統治と並べることをお勧めしますwhere

woof xs = foldr moo baaaah xs
  where
  moo :: Integer -> Integer -> Integer
  moo x 0 = 17
  moo x y = x * x + y * (y + x + 1)
  baaaah :: Integer
  baaaah = 3

-- *Main> woof [1,2]
-- 529

いくつかのものほど美しくはありませんが、インデントについて考えることの認知的負荷が軽減されるため、エラーが発生しにくくなります。(そしてオレグはそれをします!)それはすぐにこの困難も回避したでしょう。どこにでも適しているわけではないと思いますが、これはより魅力的で、インデントの質問がより明確になる可能性があります。

 woof xs = foldr moo baaaah xs where
   moo :: Integer -> Integer -> Integer
   moo x 0 = 17
   moo x y = x * x + y * (y + x + 1)
   baaaah :: Integer
   baaaah = 3

次に、where句の定義のリストは、「左マージン」と並んでいるHaskellモジュールの定義のリストに似ていることがわかります。

于 2011-08-24T16:04:51.997 に答える