Is there a way to do partial/curried type arguments?

Hello dear Haskell friends.

Sometimes I have a function like this:

f a b c d e = .... h b e

But then, occasionally, in order to evaluate h I need a type application like:

f a b c d e = .... h @blike b e

where blike is some type that none of the other variables have.

Then I feel extreme sadness, as in order to do that I need to completely define the type of f:

f :: forall ... b. ( BLike b, ... )

occasionally, this is super annoying, because the type is really long.

it’d be so convenient if I could just somehow label the one type that I’d like to use as a type application, just like I can do for function arguments; i.e. can I curry these forall things?

Is there a way to do this?

[ edit: I’ve updated the original question since @jaror pointed out it was a bit wrong initially. ]

Can you give a complete example? I don’t understand why the @BLike type application forces the type of f to be manually defined.

I share the same confusion with @jaror, but if all you want to do is to provide a partial type signature for f, you can take a look at the partial type signatures extension.

PartialTypeSignatures doesn’t let me name a type variable and use it though, does it?

Can you give a complete example? I don’t understand why the @BLike type application
forces the type of f to be manually defined.

Sorry, I slightly messed up my example; to be more clear, what I would like to write is:

f a b c d e = .... h @blike b e

with:

f :: forall ... blike. ( BLike blike, ... )

then when I call f i’d do:

f @SomeBThing ...

I hope this is more clear. I’ll try and come up with some real code later this afternoon. (Edit: this example may be slightly overcomplicated, but I hope it indicates the essential idea; partially defining the type variables with forall, and then applying them.)

If blike is the type of one of the arguments, then you can use pattern signatures:

f a (b :: blike) c d e = ... h @blike b e

But I don’t know if that is applicable to your use-case.

unfortunately in my case the blike class is not a type of anything I provide; i.e. it’s not a type of any of the arguments; it’s merely related; hence the need to pass it in as a type argument.

Indeed, I can “solve” my problem like so:

f a b c d e (dummy :: blike) = ... h @blike b e
f aValue bValue ... (undefined :: SomeBThing)

which is horrible, but somehow way nicer than writing out a very large type, almost all of which is irrelevant.

So it seems like you want to be able to write something like

f @blike a b c d e = ... h @blike b e

That’s not possible as far as I know (although I don’t know why not).

1 Like

Oh, but maybe you’d like to know the Proxy trick. You can write

f a b c d e (_ :: proxy blike) = ... h @blike b e

f aValue bValue ... (Proxy :: Proxy SomeBThing)

or even

f aValue bValue ... (Nothing :: Maybe SomeBThing)

if you want to avoid importing Data.Proxy. And with TypeApplications the following are not too bad:

f aValue bValue ... (Proxy @SomeBThing)
f aValue bValue ... (Nothing @SomeBThing)

So it seems like you want to be able to write something like

f @blike a b c d e = ... h @blike b e

Yes exactly!

I think I’m familiar with the Proxy stuff; but in this case I don’t think adding Proxy really helps me; when doing the ugly undefined thing just works (horrible though it is.)

In this case you could use {-# LANGUAGE AllowAmbiguousTypes #-} and if you define

f ::
  forall blike a b c d e.
  a -> b -> c -> d -> e
f = ... h @blike b e

And then at the call-site: f @blike a b c d e will just work. (note that blike should be the first in the forall list so that it’s the first to be filled when using f @something)

I’ve heard of actual type arguments coming to GHC in the near(-ish) future, so that would also solve this for you.

From his original message I got the impression that @silky wanted to avoid an explicit signature for f.

Ah, right. I thought they meant that they’d need to add in constraints on blike which they didn’t want to do.

Hmmm, yeah then there’s not much other than the Proxy argument trick or waiting for actual type arguments to be added to GHC :upside_down_face:

2 Likes

Looks like they’ll be in GHC 9.10.

3 Likes