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

Haskell - образец, соответствующий синтаксическому сахару, и где

Часто у меня есть функция такого шаблона:

f :: a -> b
f x = case x of
  ... -> g ...
  ... -> g ...
  ...
  ... -> g ...
  where g = ...

В этом случае существует синтаксический сахар:

f :: a -> b
f ... = g ...
f ... = g ...
...
f ... = g ...

К сожалению, я не могу прикрепить к нему where: я, очевидно, получаю кучу not in scope s. Я могу сделать g отдельную функцию, но это не приятно: мое пространство имен модулей будет загрязнено функциями утилиты. Есть ли способ обхода?

4b9b3361

Ответ 1

Я думаю, что ваш первый пример неплох. Единственный синтаксический вес: case x of, плюс -> вместо =; последнее компенсируется тем фактом, что вы можете опустить имя функции для каждого предложения. Действительно, даже предложенная dflemstr go вспомогательная функция синтаксически тяжелее.

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

Ответ 2

Нет, нет обходного пути. Когда у вас есть несколько предложений для такой функции, они не могут использовать where -clause. Ваш единственный вариант - использовать оператор case или сделать что-то вроде этого:

f x =
  go x
  where
    go ... = g ...
    go ... = g ...
    g = ...

... если вы действительно хотите использовать форму функции по какой-либо причине.

Ответ 3

f = g . h  -- h is most of your original f
  where h ... = ...
        h ... = ...
        g = 

Ответ 4

Из Haskell 2010 on или с GHC вы также можете:

f x 
    | m1 <- x = g
    | m2 <- x = g
    ...
    where g =

но обратите внимание, что вы не можете использовать переменные, связанные с шаблонами в g. Это эквивалентно:

f x = let g = ... in case () of
     () -> case x of 
          m1 -> g
          _  -> case x of
              m2 -> g
              ....

Ответ 5

Ваше оригинальное решение кажется лучшим и единственным решением. Синтаксически это не тяжелее прямого сопоставления шаблонов по функциональным параметрам, если даже не светлее.

Но на всякий случай, если вам нужно только проверить предварительные условия, а не совпадение с шаблоном, не забывайте о стражах, которые позволяют вам свободно обращаться к области where. Но на самом деле я не вижу ничего плохого в вашем решении case of.

f :: a -> b
f a
  | a == 2    = ...
  | isThree a = ...
  | a >= 4    = ...
  | otherwise = ...
  where isThree x = x == 3

Ответ 6

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

Работая с предположением, что f :: a -> b для некоторых a и b (возможно, полиморфных), g обязательно является некоторой функцией формы c -> d, что означает, что должен быть способ последовательно извлекать a c из a. Назовите это getC :: a -> c. В этом случае решением было бы просто использовать h . g . getC для всех случаев, где h :: d -> b.

Но предположим, что вы не всегда можете получить c из a. Возможно, a имеет вид f c, где f есть Functor? Тогда вы могли бы fmap g :: f c -> f d, а затем каким-то образом преобразовать f d в b.

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

Ответ 7

С помощью LambdaCase вы также можете сделать это:

{-# language LambdaCase #-}

f :: a -> b
f = \case
  ... -> g ...
  ... -> g ...
  ...
  ... -> g ...
  where g = ...