Opened 3 years ago
Last modified 3 years ago
#10794 new feature request
Extension request: "where" clauses in type signatures
| Reported by: | danso | Owned by: | |
|---|---|---|---|
| Priority: | lowest | Milestone: | |
| Component: | Compiler (Type checker) | Version: | 7.10.2 |
| Keywords: | Cc: | ||
| Operating System: | Unknown/Multiple | Architecture: | Unknown/Multiple |
| Type of failure: | None/Unknown | Test Case: | |
| Blocked By: | Blocking: | ||
| Related Tickets: | Differential Rev(s): | ||
| Wiki Page: |
Description (last modified by )
Some type signatures could be simplified by separating certain elements, either because they are lengthy and can be expressed simpler, to better express intention, or because they are repetitive. A "WhereSignatures" extension would allow for type signatures like the following:
fold :: f -> [a] -> a where f = a -> a -> a -- expresses intention more clearly than: fold :: (a -> a -> a) -> [a] -> a union :: a -> a -> a where a = Map.Map k v -- much shorter/more readable than: union :: Map.Map k v -> Map.Map k v -> Map.Map k v
Or maybe even:
fmap :: (a -> b) -> f a -> f b where (Functor f) -- arguably prettier than: fmap :: (Functor f) => (a -> b) -> f a -> f b
This minor syntactic sugar is essentially equivalent to local "type" definitions, which provides an advantage of making the type's purpose more clear. This seems like a natural development on what the type checker can do.
Change History (7)
comment:1 follow-up: 3 Changed 3 years ago by
comment:2 Changed 3 years ago by
| Description: | modified (diff) |
|---|
comment:3 Changed 3 years ago by
Replying to nomeata:
fold :: f -> [a] -> a where f :: a -> a -> ais certainly confusing, because in the first line
fis used like a type, but in the second,fis used like a value (ora -> a -> ais used like a kindMaybe you meant
fold :: f -> [a] -> a where f = a -> a -> a
Good catch. I agree that your suggestion makes more sense and have changed the ticket accordingly.
comment:4 follow-up: 5 Changed 3 years ago by
You can today say
fold :: (f ~ a -> a -> a)
=> f -> [a] -> [a]
which does the job reasonably. I doubt it's worth doing more.
comment:5 Changed 3 years ago by
Replying to simonpj:
fold :: (f ~ a -> a -> a)
=> f -> [a] -> [a]
But doing this changes type inference characteristics, by introducing an equality and making some type variables untouchable. This was pointed out in an earlier bug (sadly, I can't remember any search terms) that highlighted a case where the static semantics of using this sort of trick was different than the expanded form.
The place I've wanted a feature like this most is when writing intricate type families. But there, it would be necessary to allow local type family definitions in the where clause.
All that said, I'm ambivalent about this proposal as stated. It would be useful. But does Simon's trick work often enough? Is it worth specifying, developing, and maintaining this? I'm not sure.
comment:6 Changed 3 years ago by
I don't think it changes the type inference characteristics. Can you give an example?
comment:7 Changed 3 years ago by
No, I don't have one. But I'm sure that there was a ticket complaining about the weirdness of using your trick. However, several minutes of looking through a bunch of tickets has yielded nothing. Maybe I'm imagining things. Until we have evidence of the failure, I agree that we should consider your trick to be a suitable encoding of the proposed idea.

is certainly confusing, because in the first line
fis used like a type, but in the second,fis used like a value (ora -> a -> ais used like a kindMaybe you meant
which could be extended to allow
I’m sure the type level programming wizards and dependently typed programmers will have the greatest need for such an extension, and have a good opinion here.