Переменные сопоставления с образцом в операторе case в Haskell - PullRequest
11 голосов
/ 13 августа 2010

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

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

Ответы [ 3 ]

26 голосов
/ 14 августа 2010

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

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"
21 голосов
/ 13 августа 2010

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

case x of
    y -> ...

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

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

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

case x of
    "def" -> ....
8 голосов
/ 13 августа 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...