Исчерпывающий кейс с монадической гвардией

haskell pattern-matching monads

246 просмотра

4 ответа

40916 Репутация автора

У меня есть caseвыражение с относительно большим количеством шаблонов:

case x of
  ... -> ...
  ... -> ...
  ... -> ...
  ... -> ...
  ...
  _ -> ...

В одном из этих случаев есть охранник:

case x of
  ... -> ...
  ... -> ...
  ... | condition -> ...
    -- If condition is false, fall through to “Rest”.

  -- Rest:
  ... -> ...
  ... -> ...
  ...
  _ -> ...

Если охранник не совпадает, мы просто проваливаемся в оставшиеся дела, без проблем. Но теперь мне нужно проверить условие монадически, поэтому я делаю:

case x of
  ... -> ...
  ... -> ...
  ... -> do
    condition <- action
    if condition
      then ...
      else ...  -- How to fall through?

  -- Rest:
  ... -> ...
  ... -> ...
  ...
  _ -> ...

Тем не менее, я думаю, что сделал ошибку. Похоже, нет способа заставить elseветвь перейти к остальным случаям, не дублируя эти ветки или не превращая их в функцию. И так или иначе путается с проверкой исчерпанности: если я хочу добавить регистр после охраны, компилятор не знает, являются ли совпадения исчерпывающими.

Как я могу изменить эту функцию или параметризовать / обернуть тип данных, чтобы получить исчерпывающую проверку с использованием монадической защиты?

Автор: Jon Purdy Источник Размещён: 18.07.2016 05:46

Ответы (4)


3 плюса

29203 Репутация автора

Один простой вариант - взять вторую половину вашего caseблока и поместить ее в отдельную функцию.

case (x, y) of
  (Foo ..., Foo ...) -> ...
  x@(Bar ..., Bar ...) -> do
    condition <- action
    if condition
    then ...
    else rest x
  x -> rest x

rest (Baz ..., ...) = ...
rest (Var ..., ...) = ...
...
rest _ = undefined

Немного неудовлетворительно использовать undefinedв случае restсбоя ловушку паттернов, которые, по вашему мнению, должны были совпадать в первой половине исходного caseблока. Если вам удастся нарушить предварительное условие (что и (Foo, Foo)т. Д. Не совпадало), вы получите ошибку во время выполнения.

Автор: Benjamin Hodgson Размещён: 18.07.2016 06:14

3 плюса

84594 Репутация автора

Я не фанат подхода ниже, но я поделюсь им в любом случае:

fix (\proceed b -> case (x, y, b) of
  (Foo ..., Foo ..., False) -> ...
  (Bar ..., Bar ..., False) -> do
    condition <- action
    if condition
      then ...
      else proceed True
  (Baz ..., ..., _) -> ...
  (Var ..., ..., _) -> ...
  ...
) False

Дополнительный флаг bизначально ложен, поэтому все ветки считаются. Как только мы proceed, мы устанавливаем его в true, чтобы пропустить первые ветви.

Может быть или не быть статически исчерпывающим, в зависимости от фактических моделей.

Автор: chi Размещён: 18.07.2016 06:33

0 плюса

40916 Репутация автора

То , что я в конечном итоге делаю использую стек монаду оснащенную Maybeи замену caseс asumболее чем список действий, следуя эту структуру:

asum

  [ do
    pattern1 <- pure input  -- failed pattern matches fall through
    body1

  , do
    pattern2 <- pure input
    body2

  , do
    pattern1 <- pure input
    guard condition         -- guards also fall through
    body3

  , ...

  ]

Как я недавно описал в этом ответе на чужой вопрос. К сожалению, это не позволяет проводить исчерпывающую проверку.

Автор: Jon Purdy Размещён: 15.04.2018 06:05

0 плюса

16373 Репутация автора

Очевидный вопрос: не можете ли вы распутать чистое и нечистое? Без реального кода трудно сказать, но если проблема связана только с одним условием, вы можете выполнить двухуровневые сценарии с использованием Either или Maybe, которые охватывают все конкретные условия.

step <-case x of 
   pattern2 -> condition <- action
                if condition 
                then Just whatToDo
                else Nothing

   pattern5 -> condition <- action2
                if condition
                then Just whatToDo2

   _ -> Nothing

case step of
  Just action -> action
  Nothing -> case x of
       pattern 1 -> body1
       ....

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

Автор: mb14 Размещён: 15.04.2018 10:41
Вопросы из категории :
32x32