3

私は の初心者で、 Learn you a HaskellHaskellを読んでいて、そのページで関数を次のように宣言しました。

tell :: (Show a) => [a] -> String  
tell [] = "The list is empty"  
tell (x:[]) = "The list has one element: " ++ show x  
tell (x:y:[]) = "The list has two elements: " ++ show x ++ " and " ++ show y  
tell (x:y:_) = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y 

これはうまくいきます。その本は言う

この関数は、空のリスト、シングルトン リスト、2 つの要素を持つリスト、および 3 つ以上の要素を持つリストを処理するため、安全です。(x:[]) および (x:y:[]) は、[x] および [x,y] として書き換えることができることに注意してください (構文糖衣のため、括弧は必要ありません)。(x:y:_) は長さ 2 以上の任意のリストに一致するため、角括弧で書き換えることはできません。

最後の行を次のように変更して、これを実行しようとしました

-- same as before
tell [x:y:_] = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y

そしてHaskellは非常に醜いメッセージを思いつきました

    Could not deduce (a ~ [a0])
    from the context (Show a)
      bound by the type signature for tell :: Show a => [a] -> String
      at C:\Documents and Settings\Razor\Desktop\Other\baby.hs:(24,1)-(27,9
5)
      `a' is a rigid type variable bound by
          the type signature for tell :: Show a => [a] -> String
          at C:\Documents and Settings\Razor\Desktop\Other\baby.hs:24:1
    In the pattern: x : y : _
    In the pattern: [x : y : _]
    In an equation for `tell':
        tell [x : y : _]
          = "This list is long. The first two elements are: "
            ++ show x ++ " and " ++ show y
Failed, modules loaded: none.

誰が何が間違っているのか説明できますか? そして、本によると、私は のように書くことができます(x:[])([x]確かにそうしました) が、なぜ のように書くことができないのですtell (x:y:_)tell [x:y:_]? 本に説明があることは知っていますが、何が問題なのか本当に理解できませんか? 誰かがそれを明確な言葉で説明できますか?

4

2 に答える 2

9
[x:y:_]

要素が 1 つだけあるリスト (少なくとも 2 つの要素があるリスト) に一致するパターンです。

パターンはネストできるため、たとえば、空でないリストをラップする値foo (Just (x:xs)) = ...を一致させるために使用できます。Maybe [a]入れ子になったパターンは括弧で囲む必要があるかもしれませんが、必ずしもそうである必要はありません。上記では、括弧 (およびスペース) を使用して、パターンがどのように解釈されるかを強調できます。

tell [ (x:y:_) ] = "This list ..." ...

トップレベルの pattern[ element ]があり、elementそれ自体がx:y:_少なくとも 2 つの要素を持つリストに一致するパターンです。全体として、このパターンは、要素の長さが少なくとも 2 のリストである単一要素のリストに一致します。

したがって、そのパターンを

tell [x:y:_] = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y

コンパイラはtell、リストのリストを引数として受け取ると推論します。

tell :: (Show [b]) => [[b]] -> String

でもあなたのサイン

tell :: (Show a) => [a] -> String

リストのリストだけでなく、可能な要素tellの任意のリストで機能するpromise 。show

推論された型と指定された型の間の不一致は、コンパイラが不平を言うものです

    Could not deduce (a ~ [a0])

(GHC は型変数に名前を付けることにしましたがa0、私は を選びbました。それは問題ではありません)。

表記法[x]resp。[x,y,z]はシンタックス シュガーであり、リストの要素はコンマで区切られ、コンマの間には任意のパターン ([x,y,z]がパターン コンテキストで使用される場合、式コンテキストで式が使用される場合) が出現する可能性があります。たとえばx:y:_、各パターンは単一の要素に対応します。リストの。このようなパターン[x,y,z,w]は、サブパターンとまったく同じ数の要素を持つリストのみに一致します (そして、各要素は対応するサブパターンに一致する必要があります)。

また、私が得られないのは、なぜ and を and として書き換えることができる(x:[])のです(x:y:[])か?[x][x,y]

それがシンタックスシュガーです。一般的に、パターンは

  • リテラル, 'a', "example"(実際には、これはシンタックス シュガーの特殊なケースです), 3.4(これも特殊なケースです。==通常のパターンとは異なり、等価比較を使用します),
  • _何にでも一致し、何もバインドしないワイルドカード
  • name何にでも一致し、対応する引数を にバインドする識別子 、nameまたは
  • 完全に適用された値コンストラクターTrue(Just xコンストラクターが適用される引数自体がパターンであるため、上記を参照してくださいJust (x:xs))

(as-patternlist@(hd : tl)や lazy patternもあります~pattern。)

リスト構成子は[](空のリスト) と(:)(通常は "cons" と呼ばれ、要素 (構成されたリストの先頭になる) と別のリスト (末尾になる) からリストを構成し、型は(:) :: a -> [a] -> [a]) であるため、リストのコンストラクター パターンは次のとおりです。

  • []空のリストの場合、および
  • x:xs空でないリストの場合、渡されたリストの先頭を namexに、末尾をname にバインドしますxs

(:)パターンをネストできます。

x : (y : (z : ws))

の右結合性により(:)、ネストされたパターンの括弧を省略できます

x : y : z : ws

リストの場合、さらなるパターンのクラス、角括弧の間のコンマ区切りの要素のリストがあります。

[x1, x2]
[x1, x2, x3, x4]

等々、括弧内に書かれているのと正確に同じ数の要素を持つリストにマッチします。これらは、対応するコンストラクター アプリケーションよりも見やすいと考えられています。

x1 : x2 : []
x1 : x2 : x3 : x4 : []

どちらの形式のパターンも同等です (したがって、次のよう[x:y:_]に書くこともできます)

(x:y:_) : []

必要に応じて)。

x:[]のショートカットは知って[x]いますが、他のものはどうですか?

それは逆で、[x]はシュガーでx : []あり、[x,y]はシンタックス シュガーですx : (y : [])。同じやり方で、

[x:y:_]

の構文シュガーです

(x : (y : _)) : []
于 2013-05-22T13:21:58.810 に答える
2

ダニエル・フィッシャーの答えは素晴らしいですが、「何が問題なのか」という質問には答えていないと思います

簡単な答えは、コロンと角括弧リストを一緒に使用したことです。通常、いずれかの表記を使用します。例:a:b:c:[] または [a,b,c].

あなたの考えにはもう1つの落とし穴があります。「残りのリスト」と一致させる 唯一の方法は、コロン表記を使用することです。ちょうど[a,b,_]3 つの要素のリストに一致し、3 番目の要素を無視します。のように長いリストには一致しません。a:b:_

于 2013-05-22T23:49:45.267 に答える