GHC issueshttps://gitlab.haskell.org/ghc/ghc/-/issues2021-06-18T11:26:16Zhttps://gitlab.haskell.org/ghc/ghc/-/issues/20014Allow OverloadedLists to overload (:) in patterns and expressions2021-06-18T11:26:16Zsheafsam.derbyshire@gmail.comAllow OverloadedLists to overload (:) in patterns and expressions@simonpj suggested ([here](https://gitlab.haskell.org/ghc/ghc/-/merge_requests/5985?commit_id=bc20a16ec9c877e0a07c25468c9566ae6339d2c7#note_359845)) that the `OverloadedLists` extension should also overload the `(:)` constructor, both in...@simonpj suggested ([here](https://gitlab.haskell.org/ghc/ghc/-/merge_requests/5985?commit_id=bc20a16ec9c877e0a07c25468c9566ae6339d2c7#note_359845)) that the `OverloadedLists` extension should also overload the `(:)` constructor, both in expressions and patterns. This requires adding new methods to the `IsList` typeclass; Simon suggests:
```haskell
class IsList l where
type Item l
fromList :: [Item l] -> l
toList :: l -> [Item l]
fromListN :: Int -> [Item l] -> l
fromListN _ = fromList
cons :: Item l -> l -> l
unCons :: l -> Maybe (Item l, l)
```
This will allow users to write code that looks like it should work with overloaded lists, such as:
```haskell
f [] = 1
f [_] = 2
f (x:xs) = x
```
Simon notes that this will probably require a GHC proposal.https://gitlab.haskell.org/ghc/ghc/-/issues/17477Warn when [] is used with NonEmpty and OverloadedLists2021-06-18T11:25:27ZJoseph C. SibleWarn when [] is used with NonEmpty and OverloadedLists## Motivation
Consider this code:
```haskell
{-# LANGUAGE OverloadedLists #-}
import Data.List.NonEmpty
badNE :: NonEmpty a
badNE = []
```
`badNE` will be bottom at runtime, despite a lack of warnings at compile time.
## Proposal
...## Motivation
Consider this code:
```haskell
{-# LANGUAGE OverloadedLists #-}
import Data.List.NonEmpty
badNE :: NonEmpty a
badNE = []
```
`badNE` will be bottom at runtime, despite a lack of warnings at compile time.
## Proposal
When the `OverloadedLists` extension is enabled, and `[]` is used in the code somewhere that a `NonEmpty` is expected, a warning should be generated. This is similar to how we currently generate a `-Woverflowed-literals` warning when a negative numeric literal is used somewhere that a `Natural` is expected.https://gitlab.haskell.org/ghc/ghc/-/issues/17219Pattern match exhaustivity warnings for overloaded lists are weirdly redundant2021-11-02T13:57:52ZSebastian GrafPattern match exhaustivity warnings for overloaded lists are weirdly redundantConsider the following program:
```haskell
{-# OPTIONS_GHC -Wincomplete-patterns #-}
{-# LANGUAGE OverloadedLists #-}
module Weird where
import Data.Sequence
f :: Seq Int -> ()
f [0] = ()
```
This elicits the following warnings:
``...Consider the following program:
```haskell
{-# OPTIONS_GHC -Wincomplete-patterns #-}
{-# LANGUAGE OverloadedLists #-}
module Weird where
import Data.Sequence
f :: Seq Int -> ()
f [0] = ()
```
This elicits the following warnings:
```
Tmp.hs:9:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘f’:
Patterns not matched:
_
_
_
|
9 | f [0] = ()
| ^^^^^^^^^^
```
This is really unhelpful. I imagine the same applies to view patterns and guards, since they all share the translation to the same `PmGrd` construct. I'd rather expect it to generate a warnings like
```
Tmp.hs:9:1: warning: [-Wincomplete-patterns]
Pattern match(es) are non-exhaustive
In an equation for ‘f’:
Patterns not matched:
[]
[p] where p is not one of {0}
(_:_:_)
|
9 | f [0] = ()
| ^^^^^^^^^^
```
... but this is of course all implicitly under the `toList` view pattern. We don't have the problem for overloaded strings, because we represent them as actual literals. We can't do the same for overloaded lists, because they actually might contain nested matches.
Whatever the solution is here, it could also be applied to overloaded literals and overloaded strings instead of the current mechanism which represents them as a special kind of literal.
This came from the warnings from `T11822` which seems to suffer from this in a very dreadful way.Sebastian GrafSebastian Grafhttps://gitlab.haskell.org/ghc/ghc/-/issues/9908Improve enumFromX support for OverloadedLists2021-06-18T11:26:45ZDavid FeuerImprove enumFromX support for OverloadedListsAt present, `OverloadedLists` desugars `[m..n]` as `fromList (enumFromTo m n)`. This is sometimes okay, but terrible for `Data.Sequence`. In particular, I want, for example,
```hs
[m..n] :: Seq Int
```
to end up as `fromFunction (n-m+1...At present, `OverloadedLists` desugars `[m..n]` as `fromList (enumFromTo m n)`. This is sometimes okay, but terrible for `Data.Sequence`. In particular, I want, for example,
```hs
[m..n] :: Seq Int
```
to end up as `fromFunction (n-m+1) (+m)`, which performs much better. There are a few approaches that look reasonable:
1. Try to catch `fromList (enumFromTo m n)` before `enumFromTo` becomes `eftInt`. This does not, unfortunately, seem to work.
1. Grab `eftInt` after it gets written back from `eftIntFB`. This would probably work, but it's currently impossible because `eftInt` is not exported from `GHC.Exts` or even `GHC.Enum`.
1. Add `enumFromTo`, etc., to the `IsList` class. Default to the current behavior, but if possible use `fromListN` for well-known `Enum` types.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | ------------------------------------ |
| Version | 7.9 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Core Libraries |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | core-libraries-committee@haskell.org |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Improve enumFromX support for OverloadedLists","status":"New","operating_system":"","component":"Core Libraries","related":[],"milestone":"7.12.1","resolution":"Unresolved","owner":{"tag":"OwnedBy","contents":"ekmett"},"version":"7.9","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":["core-libraries-committee@haskell.org"],"type":"FeatureRequest","description":"At present, `OverloadedLists` desugars `[m..n]` as `fromList (enumFromTo m n)`. This is sometimes okay, but terrible for `Data.Sequence`. In particular, I want, for example,\r\n\r\n{{{#!hs\r\n[m..n] :: Seq Int\r\n}}}\r\n\r\nto end up as `fromFunction (n-m+1) (+m)`, which performs much better. There are a few approaches that look reasonable:\r\n\r\n1. Try to catch `fromList (enumFromTo m n)` before `enumFromTo` becomes `eftInt`. This does not, unfortunately, seem to work.\r\n\r\n2. Grab `eftInt` after it gets written back from `eftIntFB`. This would probably work, but it's currently impossible because `eftInt` is not exported from `GHC.Exts` or even `GHC.Enum`.\r\n\r\n3. Add `enumFromTo`, etc., to the `IsList` class. Default to the current behavior, but if possible use `fromListN` for well-known `Enum` types.","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1Edward KmettEdward Kmetthttps://gitlab.haskell.org/ghc/ghc/-/issues/9883Make OverloadedLists more usable by splitting the class interface2021-06-18T11:26:05Zmuesli4Make OverloadedLists more usable by splitting the class interface## Problem
While the OverloadedLists extension is very useful, it limits the types which can be used with it, by requesting too much. Assume you have a database specific DSEL which allows you to use list-like expressions in queries, it'...## Problem
While the OverloadedLists extension is very useful, it limits the types which can be used with it, by requesting too much. Assume you have a database specific DSEL which allows you to use list-like expressions in queries, it's easy to implement `fromList`, but we are unable to implement `toList` in a reasonable fashion without a backend and an existing connection.
## Proposal
Modify the class interface in a way that does not require the instance to be *listable*.
```
class IsList l where
type Item l
fromList :: [Item l] -> l
fromListN :: Int -> [Item l] -> l
```
We could then provide the pattern matching functionality on `IsList` instances with different approaches.
### Another class
Just add another class which is used to provide the `toList` function, used on pattern matches. This is the easiest approach
```
class AsList l where
type Item l
toList :: l -> [Item l]
```
Desugaring works as usual and it goes well with all structures. (The name is not the best though.)
### Using Data.Foldable
The list pattern gets desugared using Data.Foldable:
```
f :: (IsList l, Foldable l) => l -> l
f [x, y, z] = [x, y]
f l = l
```
gets something like:
```
import Data.Foldable (toList)
f :: (IsList l, Foldable l) => l -> l
f (toList -> [x, y, z]) = fromList [x, y]
f l = l
```
This approach does not go well with structures like `Data.Map`, because it expects the type constructor to take the *element type* as first argument, but we would like to have a tuple type. Maybe a wrapper could be provided, but I think it's not the way to go, as long as Data.Foldable does not use type families.
## Drawbacks
Both approaches complicate the type of list expressions. This requires a bit more of typing, but it specifies exactly which functionality you need and one can simply drop the unused one, without creating dangerous dummy implementations:
- `IsList` for overloaded list expressions
- `AsList` or `Foldable` for pattern matching
Most of the time OverloadedLists is used for convenience, so I don't expect the normal user to be really affected, library writers, specifically those who write some kind of DSEL, will have to be more precise, but get a more type-safe approach, which can not fail at runtime.
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.8.3 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | External Core |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Make OverloadedLists more usable by splitting the class interface","status":"New","operating_system":"","component":"External Core","related":[],"milestone":"⊥","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.8.3","keywords":["islist","lists,","overloaded"],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"== Problem ==\r\nWhile the OverloadedLists extension is very useful, it limits the types which can be used with it, by requesting too much. Assume you have a database specific DSEL which allows you to use list-like expressions in queries, it's easy to implement {{{fromList}}}, but we are unable to implement {{{toList}}} in a reasonable fashion without a backend and an existing connection.\r\n\r\n== Proposal ==\r\n\r\nModify the class interface in a way that does not require the instance to be ''listable''.\r\n\r\n{{{\r\nclass IsList l where\r\n type Item l\r\n fromList :: [Item l] -> l\r\n fromListN :: Int -> [Item l] -> l\r\n}}}\r\n\r\nWe could then provide the pattern matching functionality on {{{IsList}}} instances with different approaches.\r\n\r\n\r\n=== Another class ===\r\n\r\nJust add another class which is used to provide the {{{toList}}} function, used on pattern matches. This is the easiest approach\r\n{{{\r\nclass AsList l where\r\n type Item l\r\n toList :: l -> [Item l]\r\n}}}\r\n\r\nDesugaring works as usual and it goes well with all structures. (The name is not the best though.)\r\n\r\n\r\n=== Using Data.Foldable ===\r\n\r\nThe list pattern gets desugared using Data.Foldable:\r\n{{{\r\nf :: (IsList l, Foldable l) => l -> l\r\nf [x, y, z] = [x, y]\r\nf l = l\r\n}}}\r\ngets something like:\r\n{{{\r\nimport Data.Foldable (toList)\r\n\r\nf :: (IsList l, Foldable l) => l -> l\r\nf (toList -> [x, y, z]) = fromList [x, y]\r\nf l = l\r\n}}}\r\nThis approach does not go well with structures like {{{Data.Map}}}, because it expects the type constructor to take the ''element type'' as first argument, but we would like to have a tuple type. Maybe a wrapper could be provided, but I think it's not the way to go, as long as Data.Foldable does not use type families.\r\n\r\n\r\n== Drawbacks ==\r\nBoth approaches complicate the type of list expressions. This requires a bit more of typing, but it specifies exactly which functionality you need and one can simply drop the unused one, without creating dangerous dummy implementations:\r\n- {{{IsList}}} for overloaded list expressions\r\n- {{{AsList}}} or {{{Foldable}}} for pattern matching\r\nMost of the time OverloadedLists is used for convenience, so I don't expect the normal user to be really affected, library writers, specifically those who write some kind of DSEL, will have to be more precise, but get a more type-safe approach, which can not fail at runtime.","type_of_failure":"OtherFailure","blocking":[]} -->⊥https://gitlab.haskell.org/ghc/ghc/-/issues/7495generalizing overloaded list syntax to Sized Lists, HLists, HRecords, etc2021-06-18T11:25:52Znwfgeneralizing overloaded list syntax to Sized Lists, HLists, HRecords, etcFirst, sorry if I've missed an earlier request for this in trac; a few searches did not turn up anything relevant.
I've recently taken to doing a lot of work with heterogenous lists (thanks to the DataKinds work) and find the forced-con...First, sorry if I've missed an earlier request for this in trac; a few searches did not turn up anything relevant.
I've recently taken to doing a lot of work with heterogenous lists (thanks to the DataKinds work) and find the forced-cons-and-nil style of writing lists (e.g. "a:+b:+c:+HN") to be sort of unpleasant.
Would it be possible to allow rebinding list-literal syntax? Off the top of my head I think something like the following might be workable, if only I could stop \[\] and (:) from being in scope, even with -XNoImplicitPrelude. (Example requires -XDataKinds -XFlexibleInstances -XGADTs -XMultiParamTypeClasses -XTypeOperators)
```
class HasNil a where
([]) :: a
isNil :: a -> Bool
class HasCons e l l' | e l -> l', l' -> e l where
(:) :: e -> l -> l'
uncons :: l' -> Maybe (e,l)
-- For homogeneous lists...
instance HasNil [a] where
([]) = ([])
isNil = null
instance (a ~ a1, a ~ a2) => HasCons a [a1] [a2] where
(:) = (:)
uncons [] = Nothing
uncons (x:xs) = Just (x,xs)
-- For HLists...
data HList as where
HN :: HList '[]
(:+) :: a -> HList as -> HList (a ': as)
instance HasNil (HList '[]) where
([]) = HN
isNil = const True
instance (a ~ a1, as ~ as1) => HasCons a (HList as) (HList (a1 ': as1)) where
(:) = (:+)
uncons (a :+ as) = Just (a,as)
```
<details><summary>Trac metadata</summary>
| Trac field | Value |
| ---------------------- | -------------- |
| Version | 7.6.1 |
| Type | FeatureRequest |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture | |
</details>
<!-- {"blocked_by":[],"summary":"Rebindable list syntax?","status":"New","operating_system":"","component":"Compiler","related":[],"milestone":"","resolution":"Unresolved","owner":{"tag":"Unowned"},"version":"7.6.1","keywords":[],"differentials":[],"test_case":"","architecture":"","cc":[""],"type":"FeatureRequest","description":"First, sorry if I've missed an earlier request for this in trac; a few searches did not turn up anything relevant.\r\n\r\nI've recently taken to doing a lot of work with heterogenous lists (thanks to the DataKinds work) and find the forced-cons-and-nil style of writing lists (e.g. \"a:+b:+c:+HN\") to be sort of unpleasant.\r\n\r\nWould it be possible to allow rebinding list-literal syntax? Off the top of my head I think something like the following might be workable, if only I could stop [] and (:) from being in scope, even with -XNoImplicitPrelude. (Example requires -XDataKinds -XFlexibleInstances -XGADTs -XMultiParamTypeClasses -XTypeOperators)\r\n\r\n{{{\r\nclass HasNil a where\r\n ([]) :: a\r\n isNil :: a -> Bool\r\n\r\nclass HasCons e l l' | e l -> l', l' -> e l where\r\n (:) :: e -> l -> l'\r\n uncons :: l' -> Maybe (e,l)\r\n\r\n-- For homogeneous lists...\r\ninstance HasNil [a] where\r\n ([]) = ([])\r\n isNil = null\r\n\r\ninstance (a ~ a1, a ~ a2) => HasCons a [a1] [a2] where\r\n (:) = (:)\r\n uncons [] = Nothing\r\n uncons (x:xs) = Just (x,xs)\r\n\r\n-- For HLists...\r\ndata HList as where\r\n HN :: HList '[]\r\n (:+) :: a -> HList as -> HList (a ': as)\r\n\r\ninstance HasNil (HList '[]) where\r\n ([]) = HN\r\n isNil = const True\r\n\r\ninstance (a ~ a1, as ~ as1) => HasCons a (HList as) (HList (a1 ': as1)) where\r\n (:) = (:+)\r\n uncons (a :+ as) = Just (a,as)\r\n}}}","type_of_failure":"OtherFailure","blocking":[]} -->8.0.1Carter SchonwaldCarter Schonwald