Подтвердить что ты не робот

Соответствующие переменные шаблонов в случае case в Haskell

Если я сравниваю строковый литерал с строковым литералом с использованием оператора 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"

Что здесь происходит? Как это имеет смысл?

4b9b3361

Ответ 1

См. ответ "Дон" для чего. Обычная идиома для выполнения того, что вы пытаетесь сделать, такова:

var1 = "abc"
var2 = "def"

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

Конечно, в этом случае мы потеряли бы case и просто напишем охранники непосредственно на функцию:

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

UPDATE

В наши дни расширение MultiWayIf делает это со слегка меньшим синтаксическим шумом.

{-# LANGUAGE MultiWayIf #-}

foo x = if | x == var1 -> "Fail"
           | x == var2 -> "Failzor"
           | otherwise -> "WIN"

Ответ 2

Соответствие шаблону в Haskell связывает новые переменные. Поэтому, когда вы пишете:

case x of
    y -> ...

теперь вы привязали новую переменную "y" к значению "x". Это тривиальный "шаблон". Вы можете более четко увидеть, как привязка работает при использовании конструктора:

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

Теперь a и b привязываются к компонентам кортежа. И так далее для деконструкции и привязки других типов данных. Таким образом, чтобы соответствовать строковому литералу, вы должны написать:

case x of
    "def" -> ....

Ответ 3

Это потому, что "случай" не делает то, что вы думаете. "Var2", который был установлен в "def", не сравнивается с "var1" . Вместо этого вы получаете новую область, содержащую новый "var2", который привязан к значению "var1" .

Причиной сообщения об ошибке является то, что в отношении компилятора нет разницы между "var2 → ..." и "_ → ...". Оба соответствуют всем возможным значениям "var1" .