¿Por qué la instancia de funtor de 2 tuplas solo aplica la función al segundo elemento?
import Control.Applicative
main = print $ fmap (*2) (1,2)
Produce (1,4)
. Esperaría que produjera (2,4)
pero en cambio la función se aplica solo al segundo elemento de la tupla.
Actualizar Básicamente he descubierto esto casi de inmediato. Voy a publicar mi propia respuesta en un minuto..
3 answers
Déjame responder esto con una pregunta: ¿Qué salida esperas para:
main = print $ fmap (*2) ("funny",2)
Usted puede tener algo como desee (usando data Pair a = Pair a a
más o menos), pero como (,)
puede tener diferentes tipos en su primer y segundo argumento, no tiene suerte.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-18 17:59:20
La instancia Functor
es en realidad del GHC.Módulo base que es importado por Control.Applicative
.
Tratando de escribir la instancia que quiero, puedo ver que no funcionará, dada la definición de tuplas; la instancia requiere solo un parámetro de tipo, mientras que la tupla 2 tiene dos.
Una instancia válida Functor
al menos tendría que estar en tuplas, (a,a)
que tienen el mismo tipo para cada elemento, pero no se puede hacer nada furtivo, como definir la instancia en:
type T2 a = (a,a)
Porque no se permite que los tipos de instancia sean sinónimos.
El sinónimo de 2-tupla restringido anterior es lógicamente el mismo que el tipo:
data T2 a = T2 a a
Que puede tener una instancia de Funtor:
instance Functor T2 where
fmap f (T2 x y) = T2 (f x) (f y)
Como Gabriel comentó en los comentarios, esto puede ser útil para ramificar estructuras o concurrencia.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-04 23:15:25
Los pares se definen, esencialmente, de la siguiente manera:
data (,) a b = (,) a b
La clase Functor
se ve así:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Dado que los tipos de argumentos de función y los resultados deben tener tipo *
(es decir, representan valores en lugar de funciones de tipo que se pueden aplicar más o cosas más exóticas), debemos tener a :: *
, b :: *
, y, lo más importante para nuestros propósitos, f :: * -> *
. Desde (,)
tiene * -> * -> *
, debe aplicarse a un tipo de clase *
para obtener un tipo adecuado para ser un Functor
. Así
instance Functor ((,) x) where
-- fmap :: (a -> b) -> (x,a) -> (x,b)
Así que en realidad no hay manera de escribir una instancia Functor
haciendo otra cosa.
Una clase útil que ofrece más formas de trabajar con pares es Bifunctor
, de Data.Bifunctor
.
class Bifunctor f where
bimap :: (a -> b) -> (c -> d) -> f a c -> f b d
bimap f g = first f . second g
first :: (a -> b) -> f a y -> f b y
first f = bimap f id
second :: (c -> d) -> f x c -> f x d
second g = bimap id g
Esto te permite escribir cosas como las siguientes (desde Data.Bifunctor.Join
):
newtype Join p a =
Join { runJoin :: p a a }
instance Bifunctor p => Functor (Join p) where
fmap f = Join . bimap f f . runJoin
Join (,)
es entonces esencialmente lo mismo que Pair
, donde
data Pair a = Pair a a
Por supuesto, también puede usar la instancia Bifunctor
para trabajar con pares directamente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-05 04:38:31