This question is somewhat related to this earlier one:
I am trying to define a couple of semi-dependent types, which allow you to track the 'monotonicity' of functions (as described in the Monotonicity Types paper), so that the programmer does not have to do this manually (and fail at compile-time when a non-monotonic operation is passed to something that requires one).
More generally: I'd like to keep track of some 'qualifiers' of a function
Based on answers to this earlier question, I have been able to define an 'indexed category' and 'indexed arrow' where the qualifiers of h
in h = f >>> g
depend on the qualifiers of f
and g
.
This works well, as long as you only work with single-argument functions. However, (and normal arrows also have this problem), when you try to create an arrow with multiple arguments, you have the following options. (Using (+) :: Int -> Int -> Int
as example):
- Plain
arr (+)
. The result type of this will beArrow x => x Int (Int -> Int)
, since the function is curried. This means that only the first parameter is lifted into the arrow context, since the arrow 'returns a function with one parameter less'. In other words: The arrow context is not used for the rest of the arguments, so that's not what we want. arr (uncurry (+))
. The result type of this will beArrow x => x (Int, Int) Int
. Now both parameters have become part of the arrow, but we lose the ability to e.g. partially apply it. It also is not clear to me how to do uncurrying in an arity-independent way: What if we want three, four, five, ...-parameter functions?
I know it is possible to define a 'recursive typeclass' to create a polyvariadic function, such as for instance described on Rosettacode here. I have tried to define a more general function-wrapping type that might work that way, but I have not managed to do so far. I have no idea how to properly discern in the typeclass instance for a -> b
whether b
is the final result or another function (b' -> c)
, and how to extract and use the qualifier of b'
if it turns out to be the second case.
Is this possible? Am I missing something here? Or am I completely on the wrong track and is there another way to lift an n-argument function into an arrow, regardless of the value of n?