2011-06-22 23 views
15

Mi piacerebbe avere una funzione per mappare una funzione pura in un contenitore o sequenziare un'azione applicativa/monadica attraverso di essa. Per la mappatura pura abbiamoIl functor è per (a -> b) -> (f a -> f b), a cosa serve (Categoria c) => c a b -> c (f a) (f b)?

fmap :: Functor f => (a -> b) -> (f a -> f b) 

per il sequenziamento monadica abbiamo (da Data.Taversable)

mapM :: (Traversable f, Monad m) => (a -> m b) -> (f a -> m (f b)) 

che è simile a

mapKleisli :: (Traversable f, Monad m) => Kleisli m a b -> Kleisli m (f a) (f b) 
mapKleisli = Kleisli . mapM . runKleisli 

Sappiamo entrambi (->) e (Kleisli m) sono categorie (e frecce). Quindi è naturale fare una generalizzazione:

mapCategory :: (X f, Category c) => c a b -> c (f a) (f b) 

Conosci una classe X con un metodo simile? Forse, da qualche parte in hackage? Ho provato a hoogle/hayoo ma non ho trovato nulla di appropriato.

Aggiornamento:

Ora so meglio quello che mi serve. Sia le frecce di Kleisli che (->) sono istanze di ArrowApply che è potente quanto Monad. Sono venuto con questa versione freccia a base di Travesable:

{-# LANGUAGE TypeOperators #-} 

import Prelude hiding (id, (.), mapM) 
import Control.Arrow 
import Control.Category 

class Traversable f where 
    traverse :: ArrowApply (~>) => f a -> (a ~> b) ~> f b 

mapArrow :: (ArrowApply (~>), Traversable f) => a ~> b -> f a ~> f b 
mapArrow a = arr (\x -> (traverse x, a)) >>> app 

instance Traversable Maybe where 
    traverse Nothing = arr (const Nothing) 
    traverse (Just x) = arr (\a -> (a, x)) >>> app >>> arr Just 

instance Traversable [] where 
    traverse [] = arr (const []) 
    traverse (x : xs) = undefined -- this is hard! 

ho potuto utilizzare solo solita applicativa basata Traversable, con identità per funzioni pure, ma non sono sicuro che sia buono. Considerare le funzioni pure come caso speciale di azioni monadiche è strano. Interpretare sia le funzioni pure che le azioni monadiche come istanze di alcune classi di azione (Categoria/Freccia/ArrowApply) mi sembra più semplice.

Domande: desideri terminare l'istanza per []? La mia opinione su ArrowApply vs Monad ha qualche senso?

risposta

10

Stai chiedendo "qualche classe X", ma dovrebbe essere abbastanza chiaro che il nome più (o forse, solo) corretto per questa classe sarebbe "Functor". Quello che vuoi è semplicemente una classe di functor definita per un'istanza arbitraria Category, anziché limitata a (->).

Ovviamente, la tua definizione è ancora limitata ai funtori (endo) da una categoria a una sottocategoria definita dal costruttore di tipi che fornisce l'istanza. Se si generalizza un po 'più, non c'è ragione per le due categorie per essere lo stesso, dando a type class something like this one:

class (Category r, Category t) => Functor f r t | f r -> t, f t -> r where 
    fmap :: r a b -> t (f a) (f b) 

Questo è ancora terribilmente limitata rispetto al pieno concetto di una funtore nella teoria delle categorie, ma vabbè .

È anche interessante osservare che questo ha ancora un costruttore di tipo (->) al suo interno - questo perché, anche se modelliamo le categorie di origine e di destinazione con istanze arbitrarie, il tutto (e in particolare, il functor stesso) esiste ancora in un certo senso in Hask, ovvero la categoria associata a (->). L'altra metà del funtore (gli oggetti di mappatura delle parti) è, grosso modo, il (->) nel tipo * -> * per il costruttore del tipo f.

+0

Grazie per la risposta, ma in questo caso ho più interesse pratico che teorico. [Nel pacchetto categorie] (http://hackage.haskell.org/packages/archive/categories/0.56.0/doc/html/Control-Categorical-Functor.html) abbiamo solo istanze di Functor (Endo) per la categoria (->) che non ci fornisce nulla di nuovo rispetto a ciò che abbiamo nella base (eccetto la classe stessa). – modular

+0

@ user713303: sei libero di scrivere le tue istanze. Ad esempio, sarebbe molto semplice farlo per le frecce di Kleisli, come hai dimostrato nella tua domanda. –

+1

Infatti, se hai in mente esempi pratici e utili, perché non li contribuisci? Ecco [la pagina github] (https://github.com/ekmett/categories) per il pacchetto. –

Problemi correlati