Steady on! You posed a question and I gave an answer. You weren't happy with that answer. I think it's a bit premature to conclude that "this function can't be written in a simple, safe way in Haskell".
> as the article I linked claims, Haskell's type system can't encode the type of the cl_map function.
Could you say where you see that claim in the article? I can see three mentions of "Haskell" in the body, two of them mentioning that one researcher's particular implementation doesn't handle this case, but not a claim that it can't be done.
> Note that the type of cl_map is perfectly static. It would be `Integer N => (a_0 ->... a_N -> r) -> [a_0] ->... [a_N] -> [r]` assuming some fictitious syntax.
OK, fine, it's a bit clearer now what you are looking for. How about this:
> cl_map (uncurry (+)) ([1,2,3], [4,5,6])
[5,7,9]
> cl_map (+3) [1,2,3]
[4,5,6]
> let max3 (x, y, z) = x `max` y `max` z
> cl_map max3 ([1,2], [3,4], [5,6])
[5,6]
Notice that the function arguments are have different,
statically-known types! The type of this miracle function? cl_map :: Default Zipper a b => (b -> r) -> a -> [r]
And the implementation? -- Type definition
newtype Zipper a b = Zipper { unZipper :: a -> ZipList b } deriving Functor
-- Instance definition
instance a ~ b => D.Default Zipper [a] b where def = Zipper ZipList
-- These three instances are in principle derivable
instance P.Profunctor Zipper where
dimap f g = Zipper . P.dimap f (fmap g) . unZipper
instance Applicative (Zipper a) where
pure = Zipper . pure . pure
f <*> x = Zipper (liftA2 (<*>) (unZipper f) (unZipper x))
instance PP.ProductProfunctor Zipper where
purePP = pure
(****) = (<*>)
Given that the only two lines that actually matter are newtype Zipper a b = Zipper { unZipper :: a -> ZipList b } deriving Functor
instance a ~ b => D.Default Zipper [a] b where def = Zipper ZipList
and the rest are boiler plate that could be auto-derived, I think this
is pretty satisfactory. What do you think?