#haskell
#haskell
Вопрос:
Рассмотрим это:
map fromEnum $ zipWith (==) "aaaa" "abaa"
-- [1,0,1,1]
Было бы неплохо сделать здесь только один шаг:
zipWith (x y -> fromEnum (x == y)) "aaaa" "abaa"
Теперь я могу устранить y
:
zipWith (x -> fromEnum.(x ==)) "aaaa" "abaa"
Но я не могу устранить x
. Конечно, есть способы «обмануть»…
zipWith (curry (fromEnum . uncurry (==))) "aaaa" "abaa"
… но это выглядит уродливее, чем исходная лямбда.
Функция, которую я ищу, будет несколько похожа на Data.Function.on
, но «наоборот». У меня такое чувство, что для этого есть смущающе простое решение. Я что-то упускаю из виду?
Комментарии:
1. Вас беспокоит эффективность или удобочитаемость?
2. Если вы спросите меня, я нахожу первый наиболее читаемым. Может быть, написано так:
map fromEnum . zipWith (==) $ "aaaa" "abaa"
Ответ №1:
zipWith (x -> fromEnum . (x ==)) "aaaa" "abaa"
может быть записано как
zipWith (x -> (fromEnum .) (x ==)) "aaaa" "abaa"
которое можно записать как
zipWith ((fromEnum .) . (==)) "aaaa" "abaa"
Если вы найдете это читаемым, я думаю, это зависит от вкуса.
РЕДАКТИРОВАТЬ: еще один хороший способ сделать это — использовать некоторые комбинаторы Мэтта Хеллиджа:
zipWith ((==) $. id ~> id ~> fromEnum) "aaaa" "abaa"
Комментарии:
1. Когда я смотрю на этот пример, мне интересно, почему нет комбинатора типа
(a -> a -> b) -> (b -> c) -> a -> a -> c
в стиле комбинатораon :: (b -> b -> c) -> (a -> b) -> a -> a -> c
fromData.Function
.2. Вы можете определить его как .: = fmap fmap fmap .
Ответ №2:
Нет предопределенных библиотечных функций, которые выполняют именно такую композицию функций, которую вы хотите здесь. Но если вы часто используете конструкции, подобные приведенной в вопросе, вы могли бы определить такую функцию:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
g .: f = x y -> g (f x y)
x = zipWith (fromEnum .: (==)) "aaaa" "abaa"
Комментарии:
1. Также известен как комбинатор «Скараманга» или «сиськи»:
(.:) = (.) . (.)
Ответ №3:
Я определил следующие два комбинатора для приукрашивания разделов (.)
:
-
(|.>)
: Вы можете прочитать следующее определение как, разрезатьf
справа и составить сg
помощью .(|.>) :: (b -> c) -> (a -> a' -> b) -> (a -> a' -> c) f |.> g = (f .) . g
-
(<.|)
: Вы можете прочитать следующее определение как, срезатьg
слева и составить сf
помощью .(<.|) :: (a -> b -> c) -> (a' -> b) -> (a -> a' -> c) f <.| g = (. g) . f
Направление стрелки указывает направление, в котором происходит композиция. Из этих двух комбинаторов первый можно использовать в вашем примере следующим образом:
zipWith (fromEnum |.> (==)) "aaaa" "abaa"