Выписка из строя в 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 повторно используется.