You absolutely right about pattern matching (using view patterns) and [1..n]
expressions. I just missed this features of OverloadedLists
. It is not obvious how to deal with it.
My code differs from original code of this proposal, I am also not an author of proposal. Maybe @carter should start wiki page?
OverloadedLists
and stay with just list construction. It looks like implementation of generic list construction is simpler than generic pattern matching. The usability of list construction is higher because things like[ OneTypeConstructor
, OtherTypeConstructor
, "string"
]
looks more clean and simple to write than
HCons OneTypeConstructor $
HCons OtherTypeConstructor $
HCons "string" HNil
but when you pattern match some list you probably expect some concrete list type, not just some list (heterogeneous or homogeneous) with some elements.
Maybe add separate OverloadedListPatterns
extension instead?
[a,b..c]
: There should nothing changed for homogeneous lists, but heterogeneous lists can not be constructed dynamically, especially lists like [1..]
. Maybe it would be nice to make sugar [a,b..f]
unwrap toHCons a $
HCons b $
HCons c $
HCons e $
HCons f HNil
but it is not an option for homogeneous lists, especially lists like [1,2..10000000]
.
Maybe special syntax like [1,2...5]
(three dots) for constructing heterogeneous lists at compile time?
OverloadedLists
can do and this new can not. Maybe some issues with type inference ...Your example is much more complex, why so many parameters in HetCons
and functional dependencies?
Pattern matching overload is interesting idea. Pattern (x:xs)
should be considered by compiler as HCons x xs
for HList
, but compiler knowns about HList
just after type inference and see pattern (x:xs)
after parsing and desugaring, so pattern (x:xs)
must be replaced with HCons x xs
after type inference somehow. I am not very familiar with GHC internals anyway.
Hello. I propose little different solution. I dont think we should put methods isNil
and uncons
inside of this proposal, because they do not relate with lists construction. Here is full example of my proposal:
{-# LANGUAGE
FlexibleInstances
, TypeOperators
, TypeFamilies
, DataKinds
, GADTs
#-}
import GHC.TypeLits
-- | Types which can be constructed with 'cons' should instantiate this
class Cons a where
type Head a :: *
type Tail a :: *
cons :: Head a -> Tail a -> a
-- | And types which is a empty list should instantiate this
class Nil a where
nil :: a
---------------------------------
-- Simple homogenous lists --
---------------------------------
instance Cons [a] where
type Head [a] = a
type Tail [a] = [a]
cons elem b = elem:b
instance Nil [a] where
nil = []
-- | synoym for '[10, 20, 42]'
justList :: [Int]
justList = cons 10 $ cons 20 $ cons 42 $ nil
-------------------------------
-- Simple heterogenous lists --
-------------------------------
-- | Simple heterogenous list
data HList (typs :: [*]) where
HNil :: HList '[]
HCons :: typ -> HList typs -> HList (typ ': typs)
instance Cons (HList (t ': ts)) where
type Head (HList (t ': ts)) = t
type Tail (HList (t ': ts)) = HList ts
cons = HCons
instance Nil (HList '[]) where
nil = HNil
-- | synonym of '[10, 20, "hello"]'
hlist :: HList '[Int, Integer, String]
hlist = cons 10 $ cons 20 $ cons "hello" nil
---------------------------------------------------------------------------
-- More complex heterogenous list with constraints for it's elements --
---------------------------------------------------------------------------
-- | Checks that element contained in type list
type family Elem (typ :: *) (typs :: [*]) :: Bool where
Elem typ '[] = 'False
Elem typ (typ ': typs) = 'True
Elem typ1 (typ2 ': typs) = Elem typ1 typs
-- | Heterogenous list with uniq elements
data UniqHList (typs :: [*]) where
UHNil :: UniqHList '[]
UHCons :: ('False ~ (Elem typ typs))
=> typ -> UniqHList typs -> UniqHList (typ ': typs)
-- | Look at instance constraint, it is the same constraint as in
-- 'UHCons' constructor
instance ('False ~ (Elem t ts)) => Cons (UniqHList (t ': ts)) where
type Head (UniqHList (t ': ts)) = t
type Tail (UniqHList (t ': ts)) = UniqHList ts
cons = UHCons
instance Nil (UniqHList '[]) where
nil = UHNil
-- | This should be written as '[10, "string", 42.2, 20]'
uniqHlist :: UniqHList '[Integer, String, Double, Int]
uniqHlist = cons 10 $ cons "string" $ cons 42.2 $ cons 20 nil
---------------------------------------
-- Vectors parametrized with length --
---------------------------------------
data Vector (len :: Nat) a where
VNil :: Vector 0 a
VCons :: a -> Vector len a -> Vector (len + 1) a
-- | Look at the constraint again. It is a little hackish because GHC
-- can not infer that __len ~ ((len - 1) + 1)__
instance (len ~ ((len - 1) + 1)) => Cons (Vector len a) where
type Head (Vector len a) = a
type Tail (Vector len a) = Vector (len - 1) a
cons = VCons
instance Nil (Vector 0 a) where
nil = VNil
vector :: Vector 3 Int
vector = cons 1 $ cons 2 $ cons 3 $ nil
It is compilable and contains instances for some complex cases. The method cons
shoud be considered as (:)
and nil
should become []
.
What do you think? Cheers!
The
qualified
applies toM
but not to(Map)
.
Yes, but this syntax still looks more logical than without "qaulified". It is not obvious to see something like
import Data.Map (Map) as M
And have module Data.Map imported qualified as M.
Why not?
import qualified Data.Map (Map) as M
While it is qualified import it should have keyword "qualified" to specify that explicitly.
Hello, Simon!
Print instances of type/data families is a great idea. I also think, that we can expand the meaning of this "parentheses syntax" to general type application. So, type application can give us four variants of data depending on "type of type" of first argument:
Finite typeclass application: For finite typeclass application we can print detailed information about specific instance, for example :info (Eq Int)
must print assigned type/data families, module where instance is defined, maybe something else.
Finite data type: as application type parameters to ordinary data type with parameters. Here we can print the same as for other finite type like Int
Finite data family application: print information like for any other finite type, or, if type is not finite
Finite type family application: print type assigned to this type family.
I don't know what we must print on partial type applications in same cases, maybe just throw exception.
Unfortunately, I have no experience with GHC code base to make a patch. What do you mean about "to specify the feature" ? My English is not native...
In real life I am like a https://github.com/s9gf4ult (dont have good personal blog)
Current version of ghci (7.6.3) does not show data instances. For example, I have some Yesod application and I want to see all data constructors of (Route App) data family instance:
*Application> :info Route App
class Eq
(Route
a) => yesod-routes-1.2.0.6:Yesod.Routes.Class.RenderRoute a where
data family Route a1
...
-- Defined in `yesod-routes-1.2.0.6:Yesod.Routes.Class'
instance Eq (Route App) -- Defined at Foundation.hs:48:1
instance Read (Route App) -- Defined at Foundation.hs:48:1
.................
It just shows info about Route
, then info about App
separately. When I try this:
*Application> :info (Route App)
<interactive>:1:2: parse error on input `Route'
I am getting parse error.
I offer to use this syntax (with parentheses) to show info about instance of data/type family, namely, data constructors and such stuff, just like for ordinal data
.
Trac field | Value |
---|---|
Version | 7.6.3 |
Type | FeatureRequest |
TypeOfFailure | OtherFailure |
Priority | normal |
Resolution | Unresolved |
Component | GHCi |
Test case | |
Differential revisions | |
BlockedBy | |
Related | |
Blocking | |
CC | hvr |
Operating system | |
Architecture |