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

Haskell, где синтаксис предложения внутри блока do

Я пытаюсь реорганизовать вызов функции mapM_ внутри блока do в Haskell. Я хотел бы извлечь lambda для (локально) названной функции, чтобы сделать код более читаемым.

Мой код изначально выглядит так:

do
  -- ...
  mapM_ (\x -> x + 1) aList

  return aValue

Я хотел бы изменить его на

do
  -- ...
  mapM_ func aList
    where func x = x + 1

  return aValue

но я получаю синтаксическую ошибку в строке return aValue. Моя фактическая лямбда сложнее:-), но я попробовал ее с помощью той же лямбда, чтобы убедиться, что это не проблема в лямбда-коде.

Как я могу переписать этот код? Должен ли я использовать let... in вместо?

4b9b3361

Ответ 1

Есть три похожих (но разных) способа определения здесь:

  • Вы можете присоединить предложения where после определенных определений - в основном привязки стиля уравнения. Таким образом, вы можете поместить его в конце своей функции или после чего-то определенного с помощью let или окружения where.

  • С другой стороны, let x = ... in ... - это выражение, которое вычисляет часть после in, которая является единственным местом, где видны элементы после let.

  • Внутри блока do, потому что уже есть неявное вложение области (вещи видны после их определения), вы можете использовать только let x = .... Это действительно то же самое, что и предыдущая форма - остальная часть блока do после let является фактически частью in ....

Если вы хотите, чтобы локальное определение использовало что-то определенное в блоке do, ваш единственный выбор - третий (или передача другого значения (ов) в качестве аргумента (ов)). Однако для независимых вспомогательных функций, таких как ваш пример, работает любой стиль. Вот ваш пример, чтобы продемонстрировать каждый:

Первый стиль, где func отображается в любом месте foo, включая все, что определено в предложении where:

foo = do ...
         mapM_ func aList
         ...
         return aValue
  where func x = x + 1

Второй стиль, где func отображается только внутри выражения let, который в этом случае является целым блоком do:

foo = let func x = x + 1 
      in do 
         ...
         mapM_ func aList
         ...
         return aValue

И третий стиль, определяющий его внутри блока do. В этом случае func видна только после let; в первом ... он еще не определен.

foo = do ...
         let func x = x + 1
         mapM_ func aList
         ...
         return aValue

О, и для хорошей меры: Поскольку let ... in ... является выражением, вы также можете использовать его везде, где есть выражение, чтобы назвать некоторые локальные определения. Итак, вот еще один пример:

foo = do ...
         let func x = x + 1 in mapM_ func aList
         ...
         return aValue

Как и прежде, func отображается только внутри выражения let, которое в этом случае является единственным выражением после него, больше нигде.

Ответ 2

Другой вариант - использовать forM_ вместо mapM_, который переворачивает порядок аргументов. Затем вы можете использовать оператор $ с конечным лямбда-выражением следующим образом:

do
  forM_ aList $ \x -> do
    ...

  return aValue

Ответ 3

Не должен ли ваш where находиться в конце функции?

Вот так:

function aList aValue = do
    mapM_ func aList
    return aValue
    where func x = x + 1