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.
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.
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?
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).
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.
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.
If I understand correctly, when haskell compiler sees [foo|some dsl language inside|] it knows, that it should use parser asigned to foo on string inside of quasi-quotes.
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.
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.
> 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?
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.
> 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.
[+] [-] stingraycharles|11 years ago|reply
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
[+] [-] mietek|11 years ago|reply
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
[+] [-] conistonwater|11 years ago|reply
https://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedReco...
https://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedReco...
[+] [-] tmhedberg|11 years ago|reply
[+] [-] ximeng|11 years ago|reply
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
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
[+] [-] gregwebs|11 years ago|reply
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
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
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
EDIT: Reading the article a second time enlightened me.
[+] [-] millstone|11 years ago|reply
[+] [-] a-saleh|11 years ago|reply
If I understand correctly, when haskell compiler sees [foo|some dsl language inside|] it knows, that it should use parser asigned to foo on string inside of quasi-quotes.
Long time ago, I tried learning this using this tutorial http://quasimal.com/posts/2012-05-25-quasitext-and-quasiquot...
[+] [-] chriswarbo|11 years ago|reply
The article uses two forms of quasiquotation marks: [r| and |], and [l| and |]
For example:
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
[+] [-] slashnull|11 years ago|reply
[+] [-] eru|11 years ago|reply
[+] [-] pekk|11 years ago|reply
[+] [-] nikita-volkov|11 years ago|reply
Usable records are just an icing on the cake, but it's the cake that matters.
[+] [-] cbd1984|11 years ago|reply
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
[+] [-] chriswarbo|11 years ago|reply
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.