La categoría de conjuntos es tanto monoidal cartesiana como monoidal cocartesiana. Los tipos de isomorfismos canónicos que presencian estas dos estructuras monoidales se enumeran a continuación:
type x + y = Either x y
type x × y = (x, y)
data Iso a b = Iso { fwd :: a -> b, bwd :: b -> a }
eassoc :: Iso ((x + y) + z) (x + (y + z))
elunit :: Iso (Void + x) x
erunit :: Iso (x + Void) x
tassoc :: Iso ((x × y) × z) (x × (y × z))
tlunit :: Iso (() × x) x
trunit :: Iso (x × ()) x
A los fines de esta pregunta, defino que soy Alternativeun functor monoidal laxo desde Hask bajo el Eithertensor hasta Hask bajo el (,)tensor (y no más):
class Functor f => Alt f
where
union :: f a × f b -> f (a + b)
class Alt f => Alternative f
where
nil :: () -> f Void
Las leyes son solo las de un functor monoidal laxo.
Asociatividad:
fwd tassoc >>> bimap id union >>> union
=
bimap union id >>> union >>> fmap (fwd eassoc)
Unidad izquierda:
fwd tlunit
=
bimap nil id >>> union >>> fmap (fwd elunit)
Unidad correcta:
fwd trunit
=
bimap id nil >>> union >>> fmap (fwd erunit)
Aquí se explica cómo recuperar las operaciones más familiares para la Alternativeclase de tipos en términos de los mapas de coherencia de la codificación del functor monoidal laxo:
(<|>) :: Alt f => f a -> f a -> f a
x <|> y = either id id <$> union (Left <$> x, Right <$> y)
empty :: Alternative f => f a
empty = absurd <$> nil ()
Defino Filterablefuntores ser oplax funtores monoidales de Hask bajo el Eithertensor a Hask bajo el (,)tensor:
class Functor f => Filter f
where
partition :: f (a + b) -> f a × f b
class Filter f => Filterable f
where
trivial :: f Void -> ()
trivial = const ()
Teniendo para sus leyes solo leyes de functor monoidal laxas hacia atrás:
Asociatividad:
bwd tassoc <<< bimap id partition <<< partition
=
bimap partition id <<< partition <<< fmap (bwd eassoc)
Unidad izquierda:
bwd tlunit
=
bimap trivial id <<< partition <<< fmap (bwd elunit)
Unidad correcta:
bwd trunit
=
bimap id trivial <<< partition <<< fmap (bwd erunit)
La definición de funciones de filtro y estándar como mapMaybey filteren términos de la codificación del functor monoidal oplax se dejó como ejercicio para el lector interesado:
mapMaybe :: Filterable f => (a -> Maybe b) -> f a -> f b
mapMaybe = _
filter :: Filterable f => (a -> Bool) -> f a -> f a
filter = _
La pregunta es esta: ¿es cada Alternative Monadtambién Filterable?
Podemos tetris tetris nuestro camino a una implementación:
instance (Alternative f, Monad f) => Filter f
where
partition fab = (fab >>= either return (const empty), fab >>= either (const empty) return)
Pero, ¿es esta implementación siempre legal? ¿A veces es legal (para alguna definición formal de "a veces")? Las pruebas, contraejemplos y / o argumentos informales serían muy útiles. Gracias.

Filterableleyes son bastante débiles). @AsadSaeeduddin ¡Considera adquirir algunas habilidades interactivas de demostración de teoremas para que puedas extender la mentalidad de "usar tipos, no tu cerebro" a las pruebas también!Respuestas:
Aquí va un argumento que apoya ampliamente su hermosa idea.
Primera parte: mapMaybe
Mi plan aquí es replantear el problema en términos de
mapMaybe, con la esperanza de que hacerlo nos lleve a un terreno más familiar. Para hacerlo,Eitherusaré algunas funciones de utilidad que cambian:(Tomé los primeros tres nombres de relude , y el cuarto de errores . Por cierto, ofertas de errores
maybeToRightyrightToMaybecomonoteyhushrespectivamente, enControl.Error.Util).Como notó,
mapMaybese puede definir en términos departition:De manera crucial, también podemos dar la vuelta:
Esto sugiere que tiene sentido reformular sus leyes en términos de
mapMaybe. Con las leyes de identidad, hacerlo nos da una gran excusa para olvidarnos por completo detrivial:En cuanto a la asociatividad, podemos usar
rightToMaybeyleftToMaybedividir la ley en tres ecuaciones, una para cada componente que obtenemos de las particiones sucesivas:Parametricity significa
mapMaybees agnóstico con respecto a losEithervalores que estamos tratando aquí. Siendo así, podemos usar nuestro pequeño arsenal deEitherisomorfismos para barajar las cosas y mostrar que [I] es equivalente a [II], y [III] es equivalente a [V]. Ahora tenemos tres ecuaciones:La parametricidad nos permite tragar la
fmapin [I]:Eso, sin embargo, es simplemente ...
... que es equivalente a la ley de conservación / identidad de Witherable 's
Filterable:Eso
Filterabletambién tiene una ley de composición:¿Podemos también derivar esto de nuestras leyes? Comencemos desde [III] y, una vez más, hagamos que la parametricidad haga su trabajo. Este es más complicado, así que lo escribiré en su totalidad:
En la otra dirección:
(Nota: mientras
maybeToRight () . rightToMaybe :: Either a b -> Either () bno lo estéid, en la derivación arriba los valores de la izquierda se descartarán de todos modos, por lo que es justo tacharlo como si lo fueraid).Por lo tanto, [III] es equivalente a la ley de composición de witherable 's
Filterable.En este punto, podemos usar la ley de composición para tratar [IV]:
Esto es suficiente para mostrar que su clase equivale a una formulación bien establecida de
Filterable, que es un resultado muy bueno. Aquí hay un resumen de las leyes:Como señalan los doctores , estas son leyes de functor para un functor desde Kleisli Maybe hasta Hask .
Segunda parte: alternativa y mónada
Ahora podemos abordar su pregunta real, que era sobre mónadas alternativas. Su implementación propuesta de
partitionfue:Siguiendo mi plan más amplio, pasaré a la
mapMaybepresentación:Y así podemos definir:
O, en una ortografía sin puntos:
Algunos párrafos anteriores, noté que las
Filterableleyes dicen quemapMaybees el mapeo de morfismo de un functor desde Kleisli Maybe hasta Hask . Dado que la composición de los functores es un functor, y(=<<)el mapeo de morfismo de un functor de Kleisli f a Hask ,(maybe empty return .)el mapeo de morfismo de un functor de Kleisli Quizás a Kleisli f es suficiente paramapMaybeAMser legal. Las leyes de functor relevantes son:Esta ley de identidad es válida, así que centrémonos en la composición uno:
Por lo tanto,
mapMaybeAMes legal si esmaybe empty return . g =<< empty = emptypor algunog. Ahora, siemptyse define comoabsurd <$> nil (), como lo ha hecho aquí, podemos probarlof =<< empty = emptypara cualquierf:Intuitivamente, si
emptyestá realmente vacío (como debe ser, dada la definición que estamos usando aquí), no habrá valores parafaplicar, porf =<< emptylo que no puede resultar en nada más queempty.Un enfoque diferente aquí sería investigar la interacción de las clases
AlternativeyMonad. Da la casualidad que hay una clase de mónadas alternativas:MonadPlus. En consecuencia, un rediseñadomapMaybepodría verse así:Si bien existen diversas opiniones sobre qué conjunto de leyes es el más apropiado
MonadPlus, una de las leyes que nadie parece objetar es ...... que es precisamente la propiedad de la
emptyque estábamos discutiendo algunos párrafos anteriores. La legalidad demmapMaybesigue inmediatamente de la ley cero izquierda.(Por cierto,
Control.Monadproporcionamfilter :: MonadPlus m => (a -> Bool) -> m a -> m a, que coincide con elfilterque podemos definir usandommapMaybe).En resumen:
Sí, la implementación es legal. Esta conclusión depende del
emptyhecho de que esté vacío, como debería, o de la mónada alternativa relevante que sigue laMonadPlusley de cero a la izquierda , que se reduce a casi lo mismo.Vale la pena enfatizar que
Filterableno está subsumidoMonadPlus, como podemos ilustrar con los siguientes contraejemplos:ZipList: filtrable, pero no una mónada. LaFilterableinstancia es la misma que para las listas, a pesar deAlternativeque es diferente.Map: filtrable, pero ni mónada ni aplicativo. De hecho,Mapni siquiera puede ser aplicativo porque no hay una implementación sensata depure. Sin embargo, tiene el suyoempty.MaybeT f: mientras que sus instanciasMonady deben ser una mónada, y una definición aislada necesitaría al menos , la instancia solo requiere (cualquier cosa se puede filtrar si desliza una capa en ella).AlternativefemptyApplicativeFilterableFunctor fMaybeTercera parte: vacía
En este punto, uno todavía podría preguntarse qué tan importante es un papel
emptyo quénilrealmente juegaFilterable. No es un método de clase y, sin embargo, la mayoría de las instancias parecen tener una versión sensata del mismo.De lo único que podemos estar seguros es que, si el tipo filtrable tiene habitantes, al menos uno de ellos será una estructura vacía, porque siempre podemos tomar a cualquier habitante y filtrar todo:
La existencia de
chop, sin embargo, no significa que habrá un solonilvalor vacío, o quechopsiempre dará el mismo resultado. Consideremos, por ejemplo,MaybeT IOcuyoFilterableejemplo podría ser considerado como una forma de censurar los resultados deIOlos cálculos. La instancia es perfectamente legal, aunquechoppuede producirMaybeT IO Voidvalores distintos que conllevanIOefectos arbitrarios .En una nota final, usted ha aludido a la posibilidad de trabajar con fuertes funtores monoidales, por lo que
AlternativeyFilterableestán vinculados al hacerunion/partitionynil/trivialisomorfismos. Tenerunionypartitioncomo inversos mutuos es concebible pero bastante limitante, dado queunion . partitiondescarta cierta información sobre la disposición de los elementos para una gran parte de las instancias. En cuanto al otro isomorfismo,trivial . niles trivial, peronil . triviales interesante porque implica que solo hay unf Voidvalor único , algo que vale para una parte considerable deFilterableinstancias. Sucede que hay unaMonadPlusversión de esta condición. Si exigimos eso, para cualquieru...... y luego sustituimos la
mmapMaybeparte dos, obtenemos:Esta propiedad se conoce como la ley de cero a la derecha
MonadPlus, aunque hay buenas razones para impugnar su condición de ley de esa clase en particular.fuente
MonadeAlternativeinstancias"?MonadPlus(posiblemente visto a través de la caracterización de casi semired ) establece una conexión entreAlternativeyMonadque el "adorno monoidal sin adornos de Hask-(,)with- a Hask-with-Either" no ofrece. En cualquier caso, todavía me pregunto si hay algo más profundo sobre cómoempty, que parece extraño a laFilterabledefinición simple y, sin embargo, se siente bastante apropiado, aparece aquí.emptyes parte de la definición deAlternative. ElAlternativeyFilterablepuede estar más estrechamente relacionado al exigir queunionsea el inverso departition(y viceversa), y quetrivialsea el inverso denil(y viceversa). Esto es lo que se llama un "functor monoidal fuerte".Filterableinstancias comunes , esa propiedad sería demasiado fuerte, ya quepartitionpuede ser con pérdidas. Por ejemplo,(union . partition) [L 7, R 2, L 1, R 6]es[L 7, L 1, R 2, R 6]. La partetrivial/nilfinalmente se reduciría a tener un solof Voidvalor, lo que parece más aceptable. EnMonadPlustérminos, corresponde a la ley de derecho cero impugnadam >> mzero = mzero, que, por ejemplo, es válida para listas pero no para analizadores.empty. Esta es posiblemente la actualización final :)