2011-07-06 16 views
8

Quiero hacer algo bastante simple; Estoy usando el operador (++) con Data.Map insertWith, y funciona bien, pero quiero eliminar duplicados en el valor creado, así que quiero componerlo con nub.composición con operador diádica?

Probé (nub (++)), (nub $ (++)), (nub. (++)), todo fue inútil, ya que el tipo de (++) no coincide con el tipo esperado de nub ([a]).

Por supuesto, podría definir una función auxiliar o una lambda, pero creo que probablemente haya una composición que sería más clara.

Sugerencias, por favor!

Respuesta

10

Puede escribir esto como

((nub .) .) (++) 

Ejemplo:

Prelude Data.List> ((nub .) .) (++) [1,2,3] [3,4,5] 
[1,2,3,4,5] 

En general, usted tiene

(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) 
... 

Aquí está la derivación de esta identidad para ((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)) 

Hay una nice article sobre esto (y afines) modismos, pero está en :-(rusa

+0

Muy bien, gracias por la respuesta y la derivación. (¡Su última línea de derivación parece que puede estar en ruso !?) – guthrie

+0

igual que '(nub.). (++) ' – user102008

1

Usted puede utilizar el algo divertido de aspecto (.).(.) combinador:

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" 

Es probablemente va a ser más fácil de leer que sólo tiene que utilizar una lambda o una función auxiliar en una -clause where, sin embargo.

6

Lo que quiere Parece que hay una composición de funciones binarios y unarios, como esto:

compose :: (c -> d) -> (a -> b -> c) -> (a -> b -> d) 
compose unary binary a b = unary (binary a b) 

y le pedirá una versión libre de puntos (sin mencionar de a y b las variables). Probemos y eliminemos uno por uno. Vamos a empezar con b, usando el hecho de que f (g x) = f . g:

compose unary binary a = unary . binary a 

a es el siguiente. Vamos a desugar la expresión primera:

compose unary binary a = ((.) unary) (binary a) 

y aplicar la misma regla de composición de nuevo:

compose unary binary = ((.) unary) . binary 

Esto se puede escribir más ampliamente como:

compose unary = (.) ((.) unary) 

o incluso como

compose = (.) . (.) 

Aquí, cada (.) 'quita' un argumento de la función binaria y necesita dos porque la función es binaria. Esta expresión es muy útil cuando se generaliza para cualquier functor: fmap . fmap (tenga en cuenta que fmap es equivalente a . cuando la función se ve como un funtor). Esto le permite a la 'tira' cualquier funtor fuera, por ejemplo, puede escribir:

incrementResultsOfEveryFunctionInTwoDimentionalList :: [[String -> Integer]] -> [[String -> Integer]] 
incrementResultsOfEveryFunctionInTwoDimentionalList = fmap . fmap . fmap $ (+1) 

Por lo tanto, el resultado se convierte en:

(fmap . fmap) nub (++) 

Editar:

Creo que he encontrado la respuesta que mi cerebro estaba tratando de reproducir: Haskell function composition operator of type (c→d) → (a→b→c) → (a→b→d)

+0

Gracias, me gusta su derivación y la lógica. Ahora recuerdo que había descubierto todo esto antes para otra aplicación, y lo olvidé. Creo que puede ser conveniente pensar en cada aplicación de "." como un argumento punto de inserción. – guthrie

1

No creo que el operador de composición que desea exista como una sola función ion en cualquier biblioteca estándar. La forma más corta de escribirlo es probablemente ((.).(.)).Con la definición Functor para ((->) t), también puede escribirlo como fmap . fmap o, si prefiere fmap fmap fmap.

Todo lo anterior es bastante críptico, pero la expresión es lo suficientemente común como para que muchas personas reconozcan lo que estás haciendo.

Por cierto, es posible que desee evitar llamar funciones de dos argumentos "diádicos" en Haskell, porque si extiende esa terminología a funciones de un argumento va a realmente confundir personas.

Consulte también this question para obtener información relacionada.

También puede encontrar lots of combinators with very intuitive names en esta biblioteca.

+3

Me encantó el comentario diádico :-) – luqui

+1

@luqui: Lamentablemente, el otro término común para las funciones 2-ary es "binario", que es una jerga sobrecargada, pero es más probable que esté claro desde el contexto. Usar "monádico" en lugar de "unario" es simplemente pedir confusión masiva, desesperación, disturbios civiles e inconveniencia general. –

+0

@todos - gracias por las aclaraciones (?!) - Trataré de evitar hablar sobre los argumentos, ya que parecen ... argumentativos. :-) – guthrie