On Fri, Jan 13, 2012 at 8:52 PM, Simon Peyton-Jones <simonpj@microsoft.com> wrote:

But, the Has constraints MUST exist, in full glory, in the constraint
solver.  The only question is whether you can *abstract* over them.
Imagine having a Num class that you could not abstract over. So you
could write

  k1 x = x + x :: Float
  k2 x = x + x :: Integer
  k3 x = x + x :: Int

using the same '+' every time, which generates a Num constraint. The
type signature fixes the type to Float, Integer, Int respectively, and
tells you which '+' to use.  And that is exactly what ML does!

But Haskell doesn't.  The Coolest Thing about Haskell is that you get
to *abstract* over those Num constraints, so you can write

 k :: Num a => a -> a
 k x = x + x

and now it works over *any* Num type.

On reflection, it would be absurd not to do ths same thing for Has
constraints.  If we are forced to have Has constraints internally, it
woudl be criminal not to abstract over them.  And that is precisely
what SORF is.

So I understand that internally a Has constraint is great for resolving the type.
What is the use case for having the Has abstraction externally exposed?

I think there is a great temptation for this because we would have a functionality we can point to that has some kind of extensible record capability.

But I believe the Has abstraction to be a form of weak-typing more so than a form of extensibility. Just because 2 records have a field with the same name, even with the same type in no way signifies they are related. Instead we need a formal contract for such a relation. We already have that in type classes, and they can already be used for this very capability in a more type-safe way.

Let me give an example use case that we would be tempted to use this for: database record projections. Given a record representing a row of a database table

    data Row = Row { smallName :: String, largeVideo :: ByteString }

We may have occasions in which we just use a subset of the database/record fields.

    display :: Row -> String
    display r = smallName r

We can gain efficiency by just selecting the fields we need from the database (smallName). But now I need to re-factor all my Haskell code to have a projection of the original record with just the needed fields. I could try to make a sum type with projections, but then I need to pattern match on them. 

This seems like a great use case for a generic Has abstraction, but that broadens the types allowed to outside of just Record. Instead what I really need is a more specific Has abstraction. I want to write just:

    display ::  RowSmallName r => r -> String

So instead I should use type classes, but not something generic for all possible records, something for all possible Row projections. I do have to name the different Row types, and deal with re-factoring when field usage changes, but at least I have type-safety.

i would like to avoid re-factoring and have the compiler to generate this constraint automatically based on what fields are required in the function.

    display :: RowProjection "smallName" -> String


Ideally this information is propogated back to the point where I create the records. Using the Persistent library:

    records <- selectList [RecordSmallName .== "Bob"] []

Persistent uses Template Haskell to automatically define serializing to and from records, including the full database query projection. We could generate instances for the different available record projections automatically ahead of time. With this kind of system, we would have an amazing feature of automatic database projection for queries. But maybe this kind of system would end up with horrible error messages or have details that are very difficult to work out.

My point is that Has abstractions are weak types and that likely we should be searching for something stronger or using type classes. If I am wrong then we should have convincing use cases outlined before we make this a goal of a records implementation, and still I don't see why it needs to be a blocking requirement if we are just trying to solve the basic records issue.


Greg Weber