композиция с диадическим оператором?

Я хочу сделать что-то довольно простое; Я использую оператор (++) с данными.Карта 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, потому что если вы расширите эту терминологию до функций одного аргумента, вы собираетесь действительно запутать людей.

см. также этот вопрос для таких обсуждений.

вы можете найти много комбинаторов с очень интуитивным имена в этой библиотеке.