композиция с диадическим оператором?
Я хочу сделать что-то довольно простое; Я использую оператор (++) с данными.Карта insertWith, и он отлично работает, но я хочу исключить дубликаты в созданном значении, поэтому хочу составить его с nub.
Я пробовал (nub ( ++ )), (nub $ ( ++ )), (nub . ( ++ )), все безрезультатно, в том, что тип ( ++ ) не соответствует ожидаемому типу nub ( [a]).
Я мог бы, конечно, определить вспомогательную функцию или лямбду, но я думаю, что, вероятно, есть состав, который был бы понятнее.
советы, пожалуйста!
5 ответов
вы можете написать это как
((nub .) .) (++)
пример:
Prelude Data.List> ((nub .) .) (++) [1,2,3] [3,4,5]
[1,2,3,4,5]
В общем, у вас есть
(f . ) g x = f (g x)
((f . ) . ) g x y = f (g x y)
(((f . ) . ) . ) g x y z = f (g x y z)
((((f . ) . ) . ) . ) g x y z v = f (g x y z v)
...
вот вывод этого тождества для ((nub .) .)
:
(f . g) x = f (g x)
(nub .) :: Eq a1 => (a -> [a1]) -> a -> [a1]
(nub .) = \g x -> (nub (g x))
((nub .) .) :: Eq a2 => (a -> a1 -> [a2]) -> a -> a1 -> [a2]
((nub .) .) = ((\g x -> (nub (g x))) .) = (\g' x' -> (\g x -> (nub (g x))) (g' x'))
= \g' x' x -> (nub ((g' x') x))
есть хорошая статья об этом (и связанных) идиомах, но это на русском языке: - (
то, что вы хотите, кажется композицией двоичных и унарных функций, например:
compose :: (c -> d) -> (a -> b -> c) -> (a -> b -> d)
compose unary binary a b = unary (binary a b)
и вы просите бесплатную версию (без упоминания a
и b
переменные). Давайте попробуем устранить их одного за другим. Начнем с b
, воспользовавшись тем, что f (g x) = f . g
:
compose unary binary a = unary . binary a
a
следующий. Давайте сначала десугар выражение:
compose unary binary a = ((.) unary) (binary a)
и применить то же правило композиции опять:
compose unary binary = ((.) unary) . binary
это может быть дополнительно написано как:
compose unary = (.) ((.) unary)
или даже
compose = (.) . (.)
здесь (.)
"удаляет" аргумент от двоичной функции, и вам нужны два из них, потому что функция двоичная. Эта идиома очень полезна при обобщении для любого функтора:fmap . fmap
(заметим, что fmap
эквивалентно .
когда функция рассматривается как функтор). Это позволяет "снять" любой функтор, например, вы можете пиши:
incrementResultsOfEveryFunctionInTwoDimentionalList :: [[String -> Integer]] -> [[String -> Integer]]
incrementResultsOfEveryFunctionInTwoDimentionalList = fmap . fmap . fmap $ (+1)
Итак, ваш результат будет:
(fmap . fmap) nub (++)
Edit:
я думаю, что нашел ответ, который мой мозг пытался воспроизвести:оператор композиции функции Хаскелла типа (c→d) → (a→b→c) → (a→b→d)
эта проблема решается особенно простым и красивым способом с помощью семантический редактор комбинаторы. Совещайтесь:
ваша окончательная композиция будет выглядеть так:
(result.result) nub (++)
вы можете использовать несколько смешно выглядящий (.).(.)
комбинатора:
Prelude> :set -XNoMonomorphismRestriction
Prelude> :m + Data.List
Prelude Data.List> let f = ((.).(.)) nub (++)
Prelude Data.List> :t f
f :: Eq a => [a] -> [a] -> [a]
Prelude Data.List> f "ab" "ac"
"abc"
вероятно, будет более читаемым просто использовать лямбду или вспомогательную функцию в where
-статьи, хотя.
Я не думаю, что оператор композиции, который вы хотите, существует как одна функция в любой стандартной библиотеке. Самый короткий способ написать это, вероятно,((.).(.))
. С помощью Functor
определение ((->) t)
, вы также можете записать его как fmap . fmap
или, если вы предпочитаете fmap fmap fmap
.
все вышеперечисленное довольно загадочно, но идиома достаточно распространена, что многие люди узнают, что вы делаете.
кстати, вы можете избежать вызова функций двух аргументов " dyadic" в Haskell, потому что если вы расширите эту терминологию до функций одного аргумента, вы собираетесь действительно запутать людей.
см. также этот вопрос для таких обсуждений.
вы можете найти много комбинаторов с очень интуитивным имена в этой библиотеке.