2012-05-30 17 views
5

Estoy observando functors, functors aplicativos ... No estoy seguro de cómo llegar a donde quiero, pero tengo la sensación de que seguir los tipos debería acercarme más.¿Puedo mapear el primer elemento de un par sin flechas?

¿Hay una manera simple de hacer un map -al igual que solo se aplica al primer elemento de una 2-tupla? Tomando first de Control.Arrow y el uso de Arrow (->), esto hace el truco muy bien:

map . first :: (b -> c) -> [(b, d)] -> [(c, d)] 

Mi única preocupación es que todavía tengo que ganar una intuición real para flechas, y así probablemente voy a encontrar en aguas profundas tarde o más tarde si sigo así. Además, este parece ser un caso bastante conveniente que no se puede generalizar.

¿Puedo obtener la misma funcionalidad utilizando algo de funtores, mónadas o lo que sea, mientras voy al corazón de lo que quiero? Estaba jugando con

\f -> map (f `on` fst) 

-me gustaron las ideas, pero no pude conseguirlo.

+11

Si se utiliza una abstracción que no entiende te hace sentir incómodo, no hay * absolutamente nada * incorrecto al usar el mapa 'de la versión menos abstracta (\ (a, b) -> (fa, b))'. –

+0

¡Gracias por todas las sugerencias!Esto ha sido realmente esclarecedor. Has aceptado la respuesta más votado por ti. – Ashe

+0

Comprueba http://stackoverflow.com/questions/413930 si te sientes incómodo con 'map. primero'. – sdcvvc

Respuesta

9

Las flechas tienen buenos combinadores para operar con tuplas. ¡Casi puedes pensar en ellos como las funciones de tupla que faltan!

Así, por ejemplo,

> :t \f -> map (f *** id) 
    :: (b -> c) -> [(b, c')] -> [(c, c')] 

es una forma útil de mapear el primer componente.

+2

También puede usar (desde Control.Arrow) "map (first f)" para aplicar una función al primer elemento de un par y de manera similar "map (second f)" para aplicarlo al segundo elemento. – ozataman

5

Otra abstracción que puede hacer este tipo de cosas es un bifunctor. Edward Kmett tiene un paquete llamado bifunctors. Data.Bifunctor tiene una clase de tipo para exactamente esta funcionalidad e incluye, por ejemplo, para 2-tuplas.

1

Bueno, está el paquete BiFunctor.

O usted podría utilizar un tipo de par invertido:

data Flip a b = Flip b a 

instance Functor (Flip a) where 
    fmap f (Flip x y) = Flip (f x) y 
2

Así que usted está buscando una función del tipo (a -> b) -> (a,c) -> (b,c). Sería muy bueno si sólo podría escribir

{-# LANGUAGE TupleSections #-} 
instance Functor (,c) where 
    fmap f (x,c) = (f x, c) 

pero desafortunadamente secciones de tupla sólo funcionan en el nivel de valor. No sé si hay una razón teórica para esto; Supongo que estropea la unificación de tipo de orden superior.

Hayoo creó el paquete Data.Tuple.HT donde la función se llama mapFst.

Sin ir a los bifunctores (la instancia de BiFunctor para (,) hace realmente lo que quiere y nada más) o flechas, no hay forma de obtener lo que quiere, que yo sepa al menos.

2

Creo que el problema es que hay demasiadas maneras - Creo que me gustaría ir con el consejo de Daniel Wagner - pero aquí está otra para su diversión:

{-#LANGUAGE DeriveFunctor, MultiParamTypeClasses #-} 
import Control.Newtype 

newtype P a b = P {p:: (b, a)} deriving (Show,Eq,Ord,Functor) 
instance Newtype (P a b) (b,a) where pack = P; unpack = p 

-- *Main> fmap even ("Hi",4) 
-- ("Hi",True) 
-- *Main> map (fmap even) [("Hi",4),("Bye",5)] 
-- [("Hi",True),("Bye",False)] 
-- *Main> under P (fmap even) (4,"Hi") 
-- (True,"Hi") 
-- *Main> map (under P (fmap even)) [(4,"Hi"),(5,"Bye")] 
-- [(True,"Hi"),(False,"Bye")] 
Cuestiones relacionadas