
I can agree that for a functional language, being able to apply any reasonable function to any reasonable matching argument has to be doable, but such a fundamental operation surely needs to be simple to describe?
But it is already rather simple conceptually, it's just that Haskell's kind signature syntax makes it look hairy. I mean, if you squint enough, this: ($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b could be written like: ($) :: RuntimeRep r => (a :: TYPE Lifted) (b :: TYPE r). (a -> b) -> a -> b or like I've previously suggested (if * is the default kind and wildcards are allowed in kinds): ($) :: forall a (b :: TYPE _). (a -> b) -> a -> b I mean, perhaps the syntax could be improved, but the information that: * a is lifted and boxed * b can have any kind that has a runtime representation (so unlifted and unboxed types are ok, but data kinds are not) has to go somewhere if the ability to write levity-polymorphic functions is to be given to the user, rather than only available as a one-off hack in the compiler. Perhaps going fully dependently typed and giving up on the distinction between values and types would change that; I'm not sure how for example Idris would handle levity polymorphism. Best regards, Marcin Mrotek