top | item 8909126

I think I've solved the Haskell records problem

224 points| nikita-volkov | 11 years ago |nikita-volkov.github.io | reply

101 comments

order
[+] stingraycharles|11 years ago|reply
For the uninitiated, this solves a major (major!!) pain in the Haskell community: the lack of namespacing. If you declare two records with an 'id' field in the same module, you would get conflicts. People have been either using prefixing (fooId and barId) or splitting up modules to solve this problem, which can both considered to be ugly hacks.

I am so glad the author has been able to pull this off, and it is one of those "why didnt anybody think of this before, it is so obvious!" moments.

[+] agumonkey|11 years ago|reply
It feels unnatural to see any new feature in the Haskell world that is neither from nor in the form of a PhD paper.
[+] mietek|11 years ago|reply
> Lack of namespacing … in the same module

To clarify:

1. You can’t have more than one function with the same name in the same module.

2. Standard record accessors are functions.

[+] m_mueller|11 years ago|reply
Could you expand on what's the scope of the 'record' intrinsic? Is it used for as many things as Python's `dict`? I sure hope not, otherwise I'm wondering how anyone could have gotten much done in this language before.
[+] ximeng|11 years ago|reply
Nice article.

Could anyone comment on this:

"Haskell syntax parsing needs to be reimplemented in the “record” library"

That sounds like a big, unending task. How hard would it be for this to be implemented as an actual Haskell feature, without quasi-quoting etc.?

[+] tel|11 years ago|reply
It'd be a consensus thing more than anything else. I for one am not sure that this is a sufficiently correct feature to implement in language.

But that said, Haskell's LANGUAGE extension system does allow things like this to be easily added to the language in a smooth way.

[+] yummyfajitas|11 years ago|reply
It seems to me that most of these issues could be solved at the syntactic level simply by allowing recordval.fieldname syntax. I truly don't understand why Haskell doesn't allow this - anyone have some insight?
[+] gregwebs|11 years ago|reply
This has been proposed, and it is still a good idea if one wants to make Haskell accessible to OO programers. It would require the function composition dot to have spaces around it, which is already fairly standard practice.

However, just adding some syntax does not finish solving the problem: one still needs to figure out how to get everything to typecheck under all use cases (and all type extensions) and also to operate efficiently at runtime. This article does that (although it isn't actually explained that well in the article).

[+] tel|11 years ago|reply
Then what is the type of (\x -> x.slot). It would have to be something like `HasField "slot" b a => a -> b` which is a significant increase in complexiy. It's not just a syntactic issue.

Nice record variants which completely solve this issue at the library level, IMO, exist. But the types are more complex than what most people want to deal with in practice.

[+] joelwilliamson|11 years ago|reply
recordval.fieldname would have the same syntax as function composition func1.func2

Since you should know the type of the first argument to '.', it is possible to disambiguate, but it would be a pretty significant corner case in the grammar.

[+] eru|11 years ago|reply
And I thought lenses were the canonical solution by now?

EDIT: Reading the article a second time enlightened me.

[+] millstone|11 years ago|reply
What's a "quasi-quoter?"
[+] chriswarbo|11 years ago|reply
A quoted value is exactly what is written, for example in LISP:

    (let ((foo "hello"))
         (quote (My name is foo)))

    > (My name is foo)
An unquoted value is interpreted completely:

    (let ((foo "hello"))
        (My name is foo))

    > Error: "My" is not a function
A quasiquoted value is literal by default (like a quoted value), but we can selectively "unquote" parts, to have them interpreted:

    (let ((foo "hello"))
         (quasiquote (My name is (unquote foo))))

    > (My name is "hello")
As you can see, in LISP we can use quasiquotes on pretty much anything. Most other languages with quasiquotes only support it in strings; for example in PHP ' is the quotation mark and " is the quasiquotation mark:

    $foo = "hello";
    echo 'My name is $foo';  // Gives 'My name is $foo'
    echo "My name is $foo";  // Gives "My name is hello";
Depending on the language, some require explicit unquoting (eg. ${} syntax), others require explicit escaping (eg. \$ syntax).

The article uses two forms of quasiquotation marks: [r| and |], and [l| and |]

For example:

    person :: Person
    person =
      [r| {name = "Yuri Alekseyevich Gagarin", 
           birthday = {year = 1934, month = 3, day = 9},
           country = {name = "Soviet Union", language = "Russian"}} |]
Here the value of "person" is quasiquoted, so some parts of its contents (eg. the "{", "}", "," and "=" syntax, along with the "name, "birthday", "year", "month", "day", "country" and "language" tokens) will take their 'literal' values in the record-building language. The other values, '"Yuri Alekseyevich Gagarin"', "1934", "3", "9", '"Soviet Union"' and '"Russian"' will be interpreted as Haskell values, and the results (various Strings and Nums) will be used in the record-building language, instead of their literal tokens.
[+] dons|11 years ago|reply
Syntax macros.
[+] slashnull|11 years ago|reply
String typing to the rescue!
[+] eru|11 years ago|reply
Isn't this closer to `string-kinding'?
[+] pekk|11 years ago|reply
I think I have a radical idea: use a language which solves this problem by design from the beginning. Much simpler.
[+] nikita-volkov|11 years ago|reply
There is a problem. I know no other language, which manages to have at the same a type system as powerful, abstractions as insightful, as good a support for concurrency and parallel programming, an ecosystem as rich and which performs as well.

Usable records are just an icing on the cake, but it's the cake that matters.

[+] cbd1984|11 years ago|reply
> use a language which solves this problem by design from the beginning

Now you either give up everything else Haskell gives you, or you've created a new language. Do you see how both of those solutions are problems in and of themselves?

[+] mercurial|11 years ago|reply
While the annoyances are real, they are just that: annoyances. If you change language every time a syntactic feature (or lack thereof) irks you, you're never going to get anything done.
[+] chriswarbo|11 years ago|reply
> I think I have a radical idea: use a language which solves this problem by design from the beginning. Much simpler.

I completely disagree. It's much simpler to use a language with a few simple, powerful constructs, which can be used to build everything else as libraries.