Transforming an inner type - Haskell

Welcome to the Functional Programming Zulip Chat Archive. You can join the chat here.

Sridhar Ratnakumar

Functor won't work, but I'm looking for something that is more ... general than functor? Basically:

hmap :: (a -> b) -> f a -> f b
hmap :: (a -> b) -> f a a -> f b b
hmap :: (a -> b) -> f (g a) (h a) -> f (g b) (g b)
hmap :: (a -> b) -> f (g a) -> f (g a)
...

Does such a thing already exist?

Asad Saeeduddin

All of these are just Functor

Asad Saeeduddin

it's just a pain in the ass in Haskell to witness this Functor

Sridhar Ratnakumar

What I want:

> hmap show (Maybe 2)
Maybe "2"

> hmap show (Either [Maybe 2] (Maybe 3))
Either [Maybe "2"] (Maybe "3")
Sridhar Ratnakumar

If you fmap on Either, it is going to print: Either [Maybe 2] "Maybe 3"

Reed Mullanix

These are all Functors but not Functor if that makes sense

Sridhar Ratnakumar

Sure. How do I make it work in Haskell without having to write fmap snakes for each types?

Asad Saeeduddin

Here is a number of newtypes:

newtype Join t a = Join (t a a)
newtype Compose f g a = Compose (f (g a))
newtype Inside t f g a = Inside (t (f a) (g a))
Asad Saeeduddin

all of these have Functor instances given suitable constraints

Reed Mullanix

You gotta either scrap them typeclasses or pile up the newtypes

Asad Saeeduddin

all of your hmaps come down to applying a bunch of tedious newtypes, then using fmap, then removing all the newtypes

Georgi Lyubenov // googleson78

ApplyingVia would be amazing here

Reed Mullanix

More generally, ApplyingVia would be amazing

Georgi Lyubenov // googleson78

well not "amazing", but light years ahead of all the manual newtypes

Sridhar Ratnakumar

This would be nice:

hmap :: Generic opaque => (a -> b) -> <opaque container containing a's> -> <same container, but a replaced by b>

hmap @Int show (Either (Just 2) Nothing))

Couldn't such a function be made possible via Generics? /cc @TheMatten

Asad Saeeduddin

Personally I think ApplyingVia would just be another kludge on a big tower of kludges

Reed Mullanix

SYTC does have it's own problems, even though it is better in quite a few ways

Reed Mullanix

Instead of a newtype explosion you can have these really long chains of functions manipulating records when things could just "work"

Sandy Maguire

@Sridhar Ratnakumar you can write that function sortaaaaaaaaa

Asad Saeeduddin

The thing about functional programming is that it's about programming with long chains of functions

Asad Saeeduddin

that's sort of its specialty

Asad Saeeduddin

so you can always factor them out or import them from libraries or build them up in convenient ways

Reed Mullanix

Really what you need is some sort of type-directed term generation tool... :thinking:

Reed Mullanix

A set of tactics if you will

Sandy Maguire

i wrote a janky ass generic bitraversable instance the other day

Sandy Maguire

one that does exactly this thing you want, srid

Sandy Maguire

but it's disgusting as all hell https://github.com/isovector/hs2/blob/master/hs2-types/src/Hs2/Types/Loc.hs#L50-L138

a new, WIP Haskell compiler. Contribute to isovector/hs2 development by creating an account on GitHub.
Asad Saeeduddin

@Sridhar Ratnakumar <opaque container containing a>s is Functor

Reed Mullanix

The actual implementation is very rough, but the idea is super solid IMO

Asad Saeeduddin

@Reed Mullanix I think getting something to generate terms for you is more or less an orthogonal problem to the one of typeclasses not being first class. Type directed term generation is useful in contexts outside of typeclass dictionaries, and first class typeclass dictionaries are useful in contexts where they can't be generated from the types. There is a big overlap, but I think forcing one thing to be tied to another limits the utility of the resulting solution for both use cases

Asad Saeeduddin

I'll check it out, thanks

Reed Mullanix

To clarify, I am 100% on board with 1st class dictionaries, to the point of getting rid of typeclasses altogether and just using implicits

Reed Mullanix

The only reason people use typeclasses is for the automatic instance search, so if you add that, may as well make it programmable!

Georgi Lyubenov // googleson78

well apart from the "automatic instance search", there's also the "single instance" thing :(

Reed Mullanix

That is just a constraint on the search though!

Georgi Lyubenov // googleson78

for Sets and Maps you would want it to be active

Georgi Lyubenov // googleson78

(of note: yes, it is explored - this is exactly what instance arguments are in agda)