Can we simplify Dynamic?

Currently, data Dynamic = Dynamic TypeRep Obj deriving Typeable where type Obj = Any As a result, all of the operations must be implemented "by hand" using unsafeCoerce. The more obvious representation these days would seem to be data Dynamic where Dynamic :: Typeable a => a -> Dynamic Most of the operations then become trivial applications of Typeable functions. The only exceptions seem to be dynApply and dynApp. That there are exceptions strikes me as quite unfortunate. The easiest fix is inspired by the fact that Data.Dynamic uses funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep from Data.Typeable to decide whether to coerce. It seems reasonable to add a more informative version, something like applyTypeable :: (Typeable f, Typeable a) => proxy f -> proxy a -> (forall b . (Typeable b, f ~ (a -> b)) => r) -> Maybe r On the other hand, it would be really cool if there were some more general way to get type-level information out of Typeable instances, pattern matching on the type constructors.

I suggested this last year, see this thread https://mail.haskell.org/pipermail/libraries/2014-March/022287.html On 09/29/2015 12:51 AM, David Feuer wrote:
Currently,
data Dynamic = Dynamic TypeRep Obj deriving Typeable where type Obj = Any
As a result, all of the operations must be implemented "by hand" using unsafeCoerce. The more obvious representation these days would seem to be
data Dynamic where Dynamic :: Typeable a => a -> Dynamic
Most of the operations then become trivial applications of Typeable functions. The only exceptions seem to be dynApply and dynApp. That there are exceptions strikes me as quite unfortunate. The easiest fix is inspired by the fact that Data.Dynamic uses
funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep
from Data.Typeable to decide whether to coerce. It seems reasonable to add a more informative version, something like
applyTypeable :: (Typeable f, Typeable a) => proxy f -> proxy a -> (forall b . (Typeable b, f ~ (a -> b)) => r) -> Maybe r
On the other hand, it would be really cool if there were some more general way to get type-level information out of Typeable instances, pattern matching on the type constructors.

And indeed it's a good idea! And indeed it's happening!
See, for example, https://ghc.haskell.org/trac/ghc/wiki/Typeable
But that's now a bit out of date.
Simon PJ, Dimitrios Vytiniotis, Stephanie Weirich and I are hard at work writing a paper about all of this, and we expect the results to be in GHC 8.0, with this Dynamic:
data Dynamic where
Dynamic :: TypeRep a -> a -> Dynamic
Note that TypeRep is now indexed. This is a breaking change, and I'll admit we haven't worked out the migration path. But we're focused on figuring out, precisely, where we're going before worrying too hard about how, precisely, we shall get there.
But, a much better question from my standpoint is:
Why do you care? Why do you use Dynamic? We're actually struggling a bit in the motivation section of the paper and would love to know why you care. :)
Thanks!
Richard
On Sep 28, 2015, at 6:03 PM, Roman Cheplyaka
I suggested this last year, see this thread https://mail.haskell.org/pipermail/libraries/2014-March/022287.html
On 09/29/2015 12:51 AM, David Feuer wrote:
Currently,
data Dynamic = Dynamic TypeRep Obj deriving Typeable where type Obj = Any
As a result, all of the operations must be implemented "by hand" using unsafeCoerce. The more obvious representation these days would seem to be
data Dynamic where Dynamic :: Typeable a => a -> Dynamic
Most of the operations then become trivial applications of Typeable functions. The only exceptions seem to be dynApply and dynApp. That there are exceptions strikes me as quite unfortunate. The easiest fix is inspired by the fact that Data.Dynamic uses
funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep
from Data.Typeable to decide whether to coerce. It seems reasonable to add a more informative version, something like
applyTypeable :: (Typeable f, Typeable a) => proxy f -> proxy a -> (forall b . (Typeable b, f ~ (a -> b)) => r) -> Maybe r
On the other hand, it would be really cool if there were some more general way to get type-level information out of Typeable instances, pattern matching on the type constructors.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Sadly, I can't help with that. A while back I was doing something vaguely
"dynamic-like" but in a much more constrained context. I looked to
Data.Dynamic for inspiration and found horrors instead.
On Sep 28, 2015 6:11 PM, "Richard Eisenberg"
And indeed it's a good idea! And indeed it's happening!
See, for example, https://ghc.haskell.org/trac/ghc/wiki/Typeable But that's now a bit out of date.
Simon PJ, Dimitrios Vytiniotis, Stephanie Weirich and I are hard at work writing a paper about all of this, and we expect the results to be in GHC 8.0, with this Dynamic:
data Dynamic where Dynamic :: TypeRep a -> a -> Dynamic
Note that TypeRep is now indexed. This is a breaking change, and I'll admit we haven't worked out the migration path. But we're focused on figuring out, precisely, where we're going before worrying too hard about how, precisely, we shall get there.
But, a much better question from my standpoint is: Why do you care? Why do you use Dynamic? We're actually struggling a bit in the motivation section of the paper and would love to know why you care. :)
Thanks! Richard
On Sep 28, 2015, at 6:03 PM, Roman Cheplyaka
wrote: I suggested this last year, see this thread https://mail.haskell.org/pipermail/libraries/2014-March/022287.html
On 09/29/2015 12:51 AM, David Feuer wrote:
Currently,
data Dynamic = Dynamic TypeRep Obj deriving Typeable where type Obj = Any
As a result, all of the operations must be implemented "by hand" using unsafeCoerce. The more obvious representation these days would seem to be
data Dynamic where Dynamic :: Typeable a => a -> Dynamic
Most of the operations then become trivial applications of Typeable functions. The only exceptions seem to be dynApply and dynApp. That there are exceptions strikes me as quite unfortunate. The easiest fix is inspired by the fact that Data.Dynamic uses
funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep
from Data.Typeable to decide whether to coerce. It seems reasonable to add a more informative version, something like
applyTypeable :: (Typeable f, Typeable a) => proxy f -> proxy a -> (forall b . (Typeable b, f ~ (a -> b)) => r) -> Maybe r
On the other hand, it would be really cool if there were some more general way to get type-level information out of Typeable instances, pattern matching on the type constructors.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

I forgot to thank you and the rest for your tremendous work on this! I know
you said the page is a bit out of date, but I had an idea about
fingerprints you may want to consider if you haven't already. In
particular, the wiki page indicates that TTypeRep would have to be abstract
to prevent fingerprint forgeries, but I don't think that's necessarily
correct. I would think you could instead index the Fingerprint# type with
the type it identifies. You'd probably want to add a new magical
Fingerprinted class to produce fingerprints, and a magic function to use
them. The fingerprints could actually be used completely independently to
improve performance in contexts where the full power of TTypeRep isn't
required. Then the TTyperep nodes could hold Fingerprint#s, but themselves
be concrete. Presumably, Fingerprinted => Typeable. Maybe this idea is
crazy, but I figured I'd put it out there.
BTW, I'm a bit astonished that I managed to come up with pretty much
exactly the same function application mechanism that you gave as the most
basic sort of interface.
On Sep 28, 2015 6:11 PM, "Richard Eisenberg"
And indeed it's a good idea! And indeed it's happening!
See, for example, https://ghc.haskell.org/trac/ghc/wiki/Typeable But that's now a bit out of date.
Simon PJ, Dimitrios Vytiniotis, Stephanie Weirich and I are hard at work writing a paper about all of this, and we expect the results to be in GHC 8.0, with this Dynamic:
data Dynamic where Dynamic :: TypeRep a -> a -> Dynamic
Note that TypeRep is now indexed. This is a breaking change, and I'll admit we haven't worked out the migration path. But we're focused on figuring out, precisely, where we're going before worrying too hard about how, precisely, we shall get there.
But, a much better question from my standpoint is: Why do you care? Why do you use Dynamic? We're actually struggling a bit in the motivation section of the paper and would love to know why you care. :)
Thanks! Richard
On Sep 28, 2015, at 6:03 PM, Roman Cheplyaka
wrote: I suggested this last year, see this thread https://mail.haskell.org/pipermail/libraries/2014-March/022287.html
On 09/29/2015 12:51 AM, David Feuer wrote:
Currently,
data Dynamic = Dynamic TypeRep Obj deriving Typeable where type Obj = Any
As a result, all of the operations must be implemented "by hand" using unsafeCoerce. The more obvious representation these days would seem to be
data Dynamic where Dynamic :: Typeable a => a -> Dynamic
Most of the operations then become trivial applications of Typeable functions. The only exceptions seem to be dynApply and dynApp. That there are exceptions strikes me as quite unfortunate. The easiest fix is inspired by the fact that Data.Dynamic uses
funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep
from Data.Typeable to decide whether to coerce. It seems reasonable to add a more informative version, something like
applyTypeable :: (Typeable f, Typeable a) => proxy f -> proxy a -> (forall b . (Typeable b, f ~ (a -> b)) => r) -> Maybe r
On the other hand, it would be really cool if there were some more general way to get type-level information out of Typeable instances, pattern matching on the type constructors.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

On Sep 28, 2015, at 9:42 PM, David Feuer
I forgot to thank you and the rest for your tremendous work on this! I know you said the page is a bit out of date, but I had an idea about fingerprints you may want to consider if you haven't already. In particular, the wiki page indicates that TTypeRep would have to be abstract to prevent fingerprint forgeries, but I don't think that's necessarily correct. I would think you could instead index the Fingerprint# type with the type it identifies. You'd probably want to add a new magical Fingerprinted class to produce fingerprints, and a magic function to use them. The fingerprints could actually be used completely independently to improve performance in contexts where the full power of TTypeRep isn't required. Then the TTyperep nodes could hold Fingerprint#s, but themselves be concrete. Presumably, Fingerprinted => Typeable. Maybe this idea is crazy, but I figured I'd put it out there.
So, to paraphrase, this seems to propose two separate, similar mechanisms for almost the same thing: Fingerprinted/Fingerprint# is just like Typeable/TTypeRep, except that the former is not decomposable. In exchange, working with the former might be faster. I agree that this might work, but I'm not sure the extra layer of complexity pays its weight. Do you have an example where you think this would matter in a large way? (that is, comparing type representations in a tight loop) Also, we've made a solid restructuring of TypeRep since we last updated that page. (When we're done writing the paper [next week?] we'll update the page.) In its new form, TypeRep is decidedly abstract, but there is no more TyCon type. Instead, some TypeReps are splittable and some aren't. Richard

The potential for increased speed in limited applications was really just a
happy side effect. I was mostly thinking about reducing the extent of the
trusted code base and separating it more thoroughly from the rest. Another
feature that you may or may not be able to reproduce with your current
design is that it's possible to check types (slowly) with a higher degree
of confidence than a system offering only testing up to fingerprint
equivalence--hash functions aren't perfect.
On Sep 29, 2015 9:47 AM, "Richard Eisenberg"
On Sep 28, 2015, at 9:42 PM, David Feuer
wrote: I forgot to thank you and the rest for your tremendous work on this! I know you said the page is a bit out of date, but I had an idea about fingerprints you may want to consider if you haven't already. In particular, the wiki page indicates that TTypeRep would have to be abstract to prevent fingerprint forgeries, but I don't think that's necessarily correct. I would think you could instead index the Fingerprint# type with the type it identifies. You'd probably want to add a new magical Fingerprinted class to produce fingerprints, and a magic function to use them. The fingerprints could actually be used completely independently to improve performance in contexts where the full power of TTypeRep isn't required. Then the TTyperep nodes could hold Fingerprint#s, but themselves be concrete. Presumably, Fingerprinted => Typeable. Maybe this idea is crazy, but I figured I'd put it out there.
So, to paraphrase, this seems to propose two separate, similar mechanisms for almost the same thing: Fingerprinted/Fingerprint# is just like Typeable/TTypeRep, except that the former is not decomposable. In exchange, working with the former might be faster.
I agree that this might work, but I'm not sure the extra layer of complexity pays its weight. Do you have an example where you think this would matter in a large way? (that is, comparing type representations in a tight loop)
Also, we've made a solid restructuring of TypeRep since we last updated that page. (When we're done writing the paper [next week?] we'll update the page.) In its new form, TypeRep is decidedly abstract, but there is no more TyCon type. Instead, some TypeReps are splittable and some aren't.
Richard

They aren't perfect, but if you find an SHA collision you have a
publishable result. ;)
-Edward
On Tue, Sep 29, 2015 at 11:11 AM, David Feuer
The potential for increased speed in limited applications was really just a happy side effect. I was mostly thinking about reducing the extent of the trusted code base and separating it more thoroughly from the rest. Another feature that you may or may not be able to reproduce with your current design is that it's possible to check types (slowly) with a higher degree of confidence than a system offering only testing up to fingerprint equivalence--hash functions aren't perfect. On Sep 29, 2015 9:47 AM, "Richard Eisenberg"
wrote: On Sep 28, 2015, at 9:42 PM, David Feuer
wrote: I forgot to thank you and the rest for your tremendous work on this! I know you said the page is a bit out of date, but I had an idea about fingerprints you may want to consider if you haven't already. In particular, the wiki page indicates that TTypeRep would have to be abstract to prevent fingerprint forgeries, but I don't think that's necessarily correct. I would think you could instead index the Fingerprint# type with the type it identifies. You'd probably want to add a new magical Fingerprinted class to produce fingerprints, and a magic function to use them. The fingerprints could actually be used completely independently to improve performance in contexts where the full power of TTypeRep isn't required. Then the TTyperep nodes could hold Fingerprint#s, but themselves be concrete. Presumably, Fingerprinted => Typeable. Maybe this idea is crazy, but I figured I'd put it out there.
So, to paraphrase, this seems to propose two separate, similar mechanisms for almost the same thing: Fingerprinted/Fingerprint# is just like Typeable/TTypeRep, except that the former is not decomposable. In exchange, working with the former might be faster.
I agree that this might work, but I'm not sure the extra layer of complexity pays its weight. Do you have an example where you think this would matter in a large way? (that is, comparing type representations in a tight loop)
Also, we've made a solid restructuring of TypeRep since we last updated that page. (When we're done writing the paper [next week?] we'll update the page.) In its new form, TypeRep is decidedly abstract, but there is no more TyCon type. Instead, some TypeReps are splittable and some aren't.
Richard
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

It seems to be a fairly popular proposal. =)
https://mail.haskell.org/pipermail/libraries/2014-August/023633.html
-Edward
On Mon, Sep 28, 2015 at 6:03 PM, Roman Cheplyaka
I suggested this last year, see this thread https://mail.haskell.org/pipermail/libraries/2014-March/022287.html
On 09/29/2015 12:51 AM, David Feuer wrote:
Currently,
data Dynamic = Dynamic TypeRep Obj deriving Typeable where type Obj = Any
As a result, all of the operations must be implemented "by hand" using unsafeCoerce. The more obvious representation these days would seem to be
data Dynamic where Dynamic :: Typeable a => a -> Dynamic
Most of the operations then become trivial applications of Typeable functions. The only exceptions seem to be dynApply and dynApp. That there are exceptions strikes me as quite unfortunate. The easiest fix is inspired by the fact that Data.Dynamic uses
funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep
from Data.Typeable to decide whether to coerce. It seems reasonable to add a more informative version, something like
applyTypeable :: (Typeable f, Typeable a) => proxy f -> proxy a -> (forall b . (Typeable b, f ~ (a -> b)) => r) -> Maybe r
On the other hand, it would be really cool if there were some more general way to get type-level information out of Typeable instances, pattern matching on the type constructors.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

It seems to be a fairly popular proposal. =)
Indeed. Ben Price (now at Strathclyde) did a short internship at MSR working on this; see
https://ghc.haskell.org/trac/ghc/wiki/TypeableT
Dimitrios, Stephanie, Richard, and I are working on a paper about it, which should be out in a couple of weeks.
At that point we’ll be in a position to have a proper core-libraries-committee discussion about the right API etc; I hope we can make the result part of GHC 8.0.
But I want to get the paper out first since it gives a reasonably articulate exposition of the ideas and rationale, so that we all start on the same page.
Simon
From: Libraries [mailto:libraries-bounces@haskell.org] On Behalf Of Edward Kmett
Sent: 29 September 2015 16:53
To: Roman Cheplyaka
Cc: Haskell Libraries
Subject: Re: Can we simplify Dynamic?
It seems to be a fairly popular proposal. =)
https://mail.haskell.org/pipermail/libraries/2014-August/023633.htmlhttps://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fmail.haskell.org%2fpipermail%2flibraries%2f2014-August%2f023633.html&data=01%7c01%7csimonpj%40064d.mgd.microsoft.com%7c4a20632c14424882676b08d2c8e5fe0e%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=Q8v9rdZ4Q%2bnw7oER7kBQb42HIXiujZOEmkO%2fQPOqe0g%3d
-Edward
On Mon, Sep 28, 2015 at 6:03 PM, Roman Cheplyaka
Currently,
data Dynamic = Dynamic TypeRep Obj deriving Typeable where type Obj = Any
As a result, all of the operations must be implemented "by hand" using unsafeCoerce. The more obvious representation these days would seem to be
data Dynamic where Dynamic :: Typeable a => a -> Dynamic
Most of the operations then become trivial applications of Typeable functions. The only exceptions seem to be dynApply and dynApp. That there are exceptions strikes me as quite unfortunate. The easiest fix is inspired by the fact that Data.Dynamic uses
funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep
from Data.Typeable to decide whether to coerce. It seems reasonable to add a more informative version, something like
applyTypeable :: (Typeable f, Typeable a) => proxy f -> proxy a -> (forall b . (Typeable b, f ~ (a -> b)) => r) -> Maybe r
On the other hand, it would be really cool if there were some more general way to get type-level information out of Typeable instances, pattern matching on the type constructors.
_______________________________________________ Libraries mailing list Libraries@haskell.orgmailto:Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/librarieshttps://na01.safelinks.protection.outlook.com/?url=http%3a%2f%2fmail.haskell.org%2fcgi-bin%2fmailman%2flistinfo%2flibraries&data=01%7c01%7csimonpj%40064d.mgd.microsoft.com%7c4a20632c14424882676b08d2c8e5fe0e%7c72f988bf86f141af91ab2d7cd011db47%7c1&sdata=Yb6xCqACYgr8gw%2ffKgyGvWooH2vs1S6kriYtUAV8LQg%3d
participants (5)
-
David Feuer
-
Edward Kmett
-
Richard Eisenberg
-
Roman Cheplyaka
-
Simon Peyton Jones