Как сделать case для выражения?

Рейтинг: 1Ответов: 1Опубликовано: 22.04.2023

Хочу сделать case, который будет для некоторого числа n выдавать один результат (42), для n+1 выдавать другой (43), а для всего остального — третий (44). Пытаюсь сделать так:

f x = let n = 4 in case x of {n -> 42; n+1 -> 43; _ -> 44}

Не работает. Думаю, потому что нельзя использовать выражения (n+1) в паттернах. Пытаюсь через гварды:

f x = let n=4 in case x of {n -> 42; _ | x == n+1 -> 43 | True -> 44}

Тоже не работает. Пишет, что лишний паттерн. Как сделать правильно короче всего?

Ответы

▲ 1Принят

Короче

Сопоставления с образцом в общем случае сравнениями не являются, и задействуют более примитивный механизм, недоступный сравнениям, однако и сами могут не все, что доступно сравнениям (например, сравнение с переменной). Но в вашем случае стоит задействовать как раз сравнения.

f x
  | x == n     = 42
  | x == n + 1 = 43
  | otherwise  = 44
  where n = 4

в сочетании с case

f x =
  let
    n = 4
   in
    case () of
      _ | x == n     -> 42
        | x == n + 1 -> 43
        | otherwise  -> 44

или даже так, хоть это и не одно и то же (сравнения тут используются в реализациях min/max)

f x = max 42 (min 44 (x + 38))

Длиннее

Сопоставлении производится

  1. с конструкторами данных, как по отдельности, так и в составе выражения например Nothing, Left 5, ([1], Just (Right 2)), []
  2. литералами 1, 'x', "test"
  3. переменными x, y, somethingElse.

Пеоеменным удачно сопоставляется любое выражение. так что они служат не для сравнивания с ними, а для связывания части сопоставляемого выражения с именем переменной. Т.е., грубо говоря, значение переменной в этом месте присваивается.

ghci> case 5 of {n -> n + 1}
6

в этом примере для всей правой части n будет равно 5

Так же и в более сложных выражениях

ghci> case Right 1 of {Left n -> -n; Right n -> n}
1
ghci> case Left 2 of {Left n -> -n; Right n -> n}
-2

Смысл здесь такой: если выражение Left 2 соответствует образцу Left n, чему при этом будет равно n? В данном случае двум.

Даже если одноименная переменная уже существует, в правой части сопоставления она будет затенена. Поэтому два примера будут иметь одинаковый результат (а значение 0 переменной n задействовано не будет)

ghci> let n = 0 in case 5 of {n -> n + 1}
6
ghci> let n = 0 in case 5 of {m -> m + 1}
6

Выражения n + k в сопоставлении с образцом когда-то были частью языка. Они поддерживаются компилятором и сейчас, но по умолчанию отключены, да и все равно делают не то, чего вам хотелось бы.

ghci> :set -XNPlusKPatterns
ghci> case 5 of {n + 1 -> n}
4

Т.е. в данном случае мы сопоставляем 5 с образцом n + 1, и тогда n будет равна четырем, так как если бы имея n = 4 мы прибавили бы к ней 1, то получили бы 5.