14

case ステートメントを使用して文字列リテラルを文字列リテラルと比較すると、期待どおりの動作が得られます。同じ場合は一致し、そうでない場合は一致しません。

ただし、文字列リテラルを文字列である定数と比較すると、「パターンの一致が重複しています」という警告が表示され、定数を持つ分岐は常に一致します。

セッションの例を次に示します。

Prelude> let var1 = "abc"
Prelude> let var2 = "def"
Prelude> case var1 of { var2 -> "Fail"; _ -> "Win" }

<interactive>:1:0:
    Warning: Pattern match(es) are overlapped
             In a case alternative: _ -> ...
"Fail"
Prelude> case "abc" of { var2 -> "Fail"; _ -> "Win" }

<interactive>:1:0:
    Warning: Pattern match(es) are overlapped
             In a case alternative: _ -> ...
"Fail"
Prelude> case "abc" of { "def" -> "Fail"; _ -> "Win" }
"Win"

一方、期待どおりに動作する場合:

> Prelude> if var1 == var2 then "Fail" else "Win" 
"Win"

何が起きてる?この動作はどのように意味がありますか?

4

3 に答える 3

30

理由については、ドンの回答を参照してください。あなたがやろうとしていることをするための一般的なイディオムはこれです:

var1 = "abc"
var2 = "def"

foo x = case () of
    () | x == var1 -> "Fail"
       | x == var2 -> "Failzor"
       | otherwise -> "WIN"

もちろん、この場合は を失いcase、ガードを関数に直接書きます:

foo x | x == var1 = "Fail"
      | ...

アップデート

最近では、MultiWayIf拡張機能は構文上のノイズをわずかに減らしてこれを行います。

{-# LANGUAGE MultiWayIf #-}

foo x = if | x == var1 -> "Fail"
           | x == var2 -> "Failzor"
           | otherwise -> "WIN"
于 2010-08-13T21:13:31.123 に答える
22

Haskell のパターン マッチングは、新しい変数をバインドします。だからあなたが書くとき:

case x of
    y -> ...

これで、新しい変数 'y' が 'x' の値にバインドされました。これが些細な「パターン」です。コンストラクターが関与している場合にバインディングがどのように機能するかをより明確に確認できます。

case x of 
    (a, b) -> ...

a と b がタプルのコンポーネントにバインドされます。他のデータ型の分解とバインドについても同様です。したがって、文字列リテラルに一致させるには、次のように記述します。

case x of
    "def" -> ....
于 2010-08-13T17:27:34.797 に答える
9

それは、「ケース」があなたが思っていることをしていないからです。「def」に設定された「var2」は「var1」と比較されていません。代わりに、「var1」の値にバインドされた新しい「var2」を含む新しいスコープを取得しています。

エラー メッセージの理由は、コンパイラに関する限り、"var2 ->..." と "_ -> ..." の間に違いがないためです。どちらも「var1」のすべての可能な値に一致します。

于 2010-08-13T17:05:42.227 に答える