Выписка из строя в Haskell

Есть ли элегантная нотация для Currying аргументов функции, не соответствующей порядку в Haskell?

Например, если вы хотите разделить 2 на все элементы списка, вы можете написать

map ((/) 2) [1,2,3,4,5]

Однако, чтобы разделить все элементы списка, вам нужно определить анонимную функцию

map (\x -> x/2) [1,2,3,4,5]

Анонимные функции быстро становятся громоздкими в более сложных случаях. Я знаю, что в этом случае карта ((*) 0.5) [1,2,3,4,5] будет работать нормально, но мне интересно узнать, имеет ли Haskell более элегантный способ вычисления аргументов функции не по порядку?

Ответы

Ответ 1

В данном конкретном случае:

Prelude> map (/2) [1..5]
[0.5,1.0,1.5,2.0,2.5]

Не только вы можете использовать инфиксный оператор как обычную префиксную функцию, вы также можете частично применить ее в форме infix. Аналогично, первый пример лучше записать как map (2/) [1..5]

Кроме того, там flip, который не совсем изящный, но все же лучший вариант, доступный для обычных функций (когда вы не хотите превращать их в инфикс через обратные ссылки):

Prelude> let div' = (/)
Prelude> div' 2 1
2.0
Prelude> flip div' 2 1
0.5

Ответ 2

Для вашего второго, лямбда не нужна, просто используйте как:

map (/2) [1..5]

Форма (/2) просто означает, что вы хотите получить доступ ко второму параметру оператора. Это также возможно с первым аргументом (2/). Это называется раздел, и это действительно полезный взлом не только в кодовом гольф. Вы также можете использовать его в префиксных функциях, если вы используете их infix:

map (`div` 2) [1..5]

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

Ответ 3

Я думаю, вы ищете обобщенное решение, подобное схеме cut. Правильно?

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

Ответ 4

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

dbfunc f b c = (\a -> liftIO $ f a b c)
deleteAllRows = do
  ask >>= dbfunc run "delete from t1" []

По крайней мере, этот шаблон достаточно распространен в HDBC, что dbfunc повторно используется.