L'unico `FlippyFloppyMorphism` è` const mempty`?

Sep 25 2020

In Haskell, abbiamo il fatto interessante che qualsiasi costruttore di tipo f :: * -> *che sia simultaneamente a Functore a Contravariantè fantasma nel suo parametro di tipo:

phantom :: (Functor f, Contravariant f) => f x -> f y

Un altro modo per dirlo è che ogni costruttore di tipi che è simultaneamente a se Functora Contravariantè naturalmente isomorfo a Const x, per alcuni x.

Ciò implica che l '"unico" modo (fino all'isomorfismo) per istanziare la classe:

class FlippyFloppyFunctor f
  where
  ffmap :: Either (y -> x) (x -> y) -> f x -> f y

in modo che obbedisca alle leggi del funtore:

ffmap (Left id)       = id
ffmap (Right id)      = id
ffmap (Left  (g . f)) = ffmap (Left f)  . ffmap (Left g)
ffmap (Right (f . g)) = ffmap (Right f) . ffmap (Right g)

è:

weirdmap :: Either (y -> x) (x -> y) -> Const r x -> Const r y
weirdmap = const $ \(Const x) -> Const x

cioè modulo newtype, const id.

Trovo difficile capire perché questa sia l'unica funzione del suo tipo che soddisfa i vincoli, anche se posso in qualche modo capire vari argomenti informali che coinvolgono absurd :: Void -> a/ discard :: a -> ()sul motivo per cui l'esistenza di una tale mappa implica che il funtore "è fantasma" nel suo tipo parametro.

Per capirlo meglio, ho cercato di semplificare il problema. Invece di pensare FlippyFloppyFunctor, pensiamo a:

class (Monoid a, Monoid b) => FlippyFloppyMorphism a b
  where
  ffmorph :: Either a a -> b

con leggi analoghe:

ffmorph (Left mempty)    = mempty
ffmorph (Right mempty)   = mempty
ffmorph (Left  (y <> x)) = ffmorph (Left x)  <> ffmorph (Left y)
ffmorph (Right (x <> y)) = ffmorph (Right x) <> ffmorph (Right y)

Supponendo che ae b siano monoidi non commutativi , è ancora vero che l'unica implementazione legale di FlippyFloppyMorphismè const mempty? È ancora possibile spiegare perché il morfismo deve essere "fantasma" nei monoidi in ingresso, senza avere a Voido ()a cui fare riferimento?

Risposte

1 AsadSaeeduddin Sep 25 2020 at 14:43

Mi sembra che la risposta nel caso generale sia "no", perché i monoidi possono essere commutativi.

Se il monoide è commutativo, allora Dual aè lo stesso monoide di a, ed Either a aè lo stesso di a, e quindi degeneriamo semplicemente a chiederci se ffmorphsia l'unico omomorfismo monoide a -> b. La risposta è no".

Ad esempio, per il monoide commutativo dell'addizione, abbiamo replicate 'a' :: Either (Sum Int) (Sum Int) -> String, dove:

replicateA (Left  0) = ""
replicateA (Right 0) = ""
replicateA (Left  (y + x)) = replicateA (Left x) ++ replicateA (Left y)
replicateA (Right (x + y)) = replicateA (Left x) ++ replicateA (Left y)

Tuttavia, penso che potrebbe essere il caso che per i monoidi _non_commutative, l'unica possibile implementazione sia const mempty(di cui ancora non ho una prova).