-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Heterogeneous array creation #109
base: master
Are you sure you want to change the base?
Conversation
Question: I made the heterogeneous creation functions take traversals that are polymorphic over their |
Create arbitrarily many arrays of arbitrarily many types from one `ST` action. Closes haskell#103
FYI, the higher-rank traversals are basically the ones from |
Data/Primitive/SmallArray.hs
Outdated
runSmallArrays m = runST $ m >>= traverse unsafeFreezeSmallArray | ||
|
||
-- | Create arbitrarily many arrays that may have different types. For | ||
-- a simpler but less general version, see 'runArrays'. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should say "see runSmallArrays
".
I cannot verify the soundness of this, but I like it. Also, it would be good to know the answer of your question about |
Also, I dislike the names with Het in them, but at the moment, I don’t have any better suggestions. |
The names are awful.
…On Thu, Mar 29, 2018, 4:00 AM Andrew Martin ***@***.***> wrote:
Also, I dislike the names with Het in them, but at the moment, I don’t
have any better suggestions.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#109 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_Qd-4jwDJn4wHEwTJV8_ko_rtuo-ks5tjDJFgaJpZM4S6VN1>
.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I, too, cannot offer an opinion on whether the extra polymorphism is necessary or not, but these seem like they're in the spirit of vector
's createT
, so I generally support them. (I also can't offer better naming suggestions.)
Two minor comments inline.
Data/Primitive/Array.hs
Outdated
@@ -1,6 +1,9 @@ | |||
{-# LANGUAGE CPP, MagicHash, UnboxedTuples, DeriveDataTypeable, BangPatterns #-} | |||
{-# LANGUAGE RankNTypes #-} | |||
{-# LANGUAGE TypeFamilies #-} | |||
#if __GLASGOW_HASKELL__ >= 708 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be 706? (That's the first GHC version that reliably supported PolyKinds
.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mistakenly though it didn't stabilize till later. Fixed!
Data/Primitive/SmallArray.hs
Outdated
@@ -7,6 +7,9 @@ | |||
{-# LANGUAGE DeriveDataTypeable #-} | |||
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |||
{-# LANGUAGE BangPatterns #-} | |||
#if __GLASGOW_HASKELL__ >= 708 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, 706 here.
Using runArraysHetOfThen
:: Applicative q
=> (forall s1 s2.
((forall x. MutableArray s2 x -> Compose (ST s1) q (r x)) -> t (MutableArray s2) -> Compose (ST s1) q (u r)))
-> (forall x. Array x -> q (r x))
-> (forall s. ST s (t (MutableArray s)))
-> q (u r) This reveals almost everything to the traversal function, but doesn't give it quite enough to actually monkey with the |
I've pretty much convinced myself that these are safe, even generalized considerably. See my answer to my question on SO. |
Do you mind including a summary of the rationale in that SO post somewhere in the comments? Once that's included, I'd say this is ready to be merged. |
@RyanGlScott, I added some notes, changed some types, and removed |
Oh, and a note I meant to leave earlier: I've generalized the types of |
* Add notes. * Improve some of the types. * Drop `PolyKinds`. I added it because of unclear thinking, and I don't think any of this benefits meaningfully from having it.
One more question: would |
I think it would; if other's don't disagree, I'll make that change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a strong opinion on the names, so pick whichever sounds best to you.
I’ll have a read through after I finish my other bits of review work
…On Sun, Apr 15, 2018 at 11:02 AM Ryan Scott ***@***.***> wrote:
***@***.**** approved this pull request.
I don't have a strong opinion on the names, so pick whichever sounds best
to you.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#109 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwtEVkGVM4urmTkggEaTNCFOCf8raks5to2ERgaJpZM4S6VN1>
.
|
Without `PolyKinds`, this is needed to actually make it work.
:: (forall s1 s2. | ||
((forall x. MutableArray s1 x -> ST s2 (Array x)) -> t (mut s1) -> ST s2 u)) | ||
-- ^ A rank-2 traversal | ||
-> (forall s. ST s ((t :: (* -> *) -> *) (mut s))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With PolyKinds
, this can be t :: (j -> k) -> *
. Maybe we can do that once we drop support for 7.4; until then I think it's probably a bit too much CPP for what it offers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Remember that mut
doesn't necessarily have to be used at all; it's just there to make the type match that of htraverse
. So if someone wants to use a container of MutableArray#
, say, they can still do that with a bit of type trickery.)
One thing that's still missing is a way to produce |
I deleted my last comment because it was a bit wrong, thankfully. I've been thinking some more, and there is another heterogeneous option: class Freezable m i | m -> i where
type GetS m :: *
uf :: m -> ST (GetS m) i
instance Freezable (MutableByteArray s) ByteArray where
type GetS (MutableByteArray s) = s
uf = unsafeFreezeByteArray
instance a ~ b => Freezable (MutableArray s a) (Array b) where
type GetS (MutableArray s a) = s
uf = unsafeFreezeArray
instance a ~ b => Freezable (SmallMutableArray s a) (SmallArray b) where
type GetS (SmallMutableArray s a) = s
uf = unsafeFreezeSmallArray
runVariousHetArraysOf
:: (forall s1 s2.
((forall m i. (Freezable m i, GetS m ~ s1) => m -> ST s2 i) -> t (mut s1) -> ST s2 u))
-> (forall s. ST s ((t :: k -> *) (mut s)))
-> u
runVariousHetArraysOf trav m = runST $ m >>= trav uf The nice thing is that you can run one |
Aha! I just realized something. If I modify runArraysOf
:: (forall s1 s2.
(forall x. MutableArray s1 x -> ST s2 (Array x)) -> t (mut s1 a) -> ST s2 u)
-> (forall s. ST s (t (mut s a)))
-> u then I can write runHetArraysOf trav m = runArraysOf (\f -> trav f . unT) $ T <$> m
newtype T (t :: (* -> *) -> *) (msa :: *) = T {unT :: t (Fun msa)}
type family Fun x where
Fun (f x) = f |
One thing I’ve been thinking about is maybe this set of combinators would
make more sense to live in lens. A lot of the utility seems like it’d be
highest for folks who use lense a lot. Especially the whole higher rank
traversal bit.
I guess what I mean is that comfort using these combinators seems
predicated on using lens, which is down stream of primitive.
At a philosophical level, my perspective on the primitive package is that
it’s about making the various magic hash mutable data structures ghc
provides usable from types in kind Star. Vector and similar higher level
libraries are the clients / users of primitive for their data structure
needs
The only exception is We can’t do that safely for STM Data structures in
primitive because of the no nesting transactions requirement of stm
precluding execution in any setting / prim monad aside from those with io
as the base monad.
So I guess what I’m trying to say is that I’m currently inclined to say no
to adding these traversal combinators to primitive. Though I’ll ponder
this a bit more before I take a strong stance
…On Thu, Apr 19, 2018 at 2:46 PM David Feuer ***@***.***> wrote:
Aha! I just realized something. If I modify runArraysOf very slightly, I
can actually implement runHetArraysOf on top of it! Specifically, if I
change the type signature of runArraysOf to
runArraysOf
:: (forall s1 s2.
(forall x. MutableArray s1 x -> ST s2 (Array x)) -> t (mut s1 a) -> ST s2 u)
-> (forall s. ST s (t (mut s a)))
-> u
then I can write
runHetArraysOf trav m = runArraysOf (\f -> trav f . unT) $ T <$> m
newtype T (t :: (* -> *) -> *) (msa :: *) = T {unT :: t (Fun msa)}type family Fun x where
Fun (f x) = f
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#109 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwmpclIulqGPz_AJ8czjZxoHIyoYaks5tqNuAgaJpZM4S6VN1>
.
|
That might be reasonable. On the other hand, one of the versions I
described uses a Freezable class to be able to freeze anything with a
notion of freezing. That Freezable class, to be maximally useful, should
live at the lowest level of the module hierarchy that it can. Optimally,
that would probably mean GHC.Arr, but starting it somewhere in primitive
might be a good compromise. With that class available, anyone can write a
Trustworthy version of runArraysOf with their desired type details.
On Thu, Apr 19, 2018 at 4:53 PM, Carter Tazio Schonwald <
notifications@github.com> wrote:
… One thing I’ve been thinking about is maybe this set of combinators would
make more sense to live in lens. A lot of the utility seems like it’d be
highest for folks who use lense a lot. Especially the whole higher rank
traversal bit.
I guess what I mean is that comfort using these combinators seems
predicated on using lens, which is down stream of primitive.
At a philosophical level, my perspective on the primitive package is that
it’s about making the various magic hash mutable data structures ghc
provides usable from types in kind Star. Vector and similar higher level
libraries are the clients / users of primitive for their data structure
needs
The only exception is We can’t do that safely for STM Data structures in
primitive because of the no nesting transactions requirement of stm
precluding execution in any setting / prim monad aside from those with io
as the base monad.
So I guess what I’m trying to say is that I’m currently inclined to say no
to adding these traversal combinators to primitive. Though I’ll ponder
this a bit more before I take a strong stance
On Thu, Apr 19, 2018 at 2:46 PM David Feuer ***@***.***>
wrote:
> Aha! I just realized something. If I modify runArraysOf very slightly, I
> can actually implement runHetArraysOf on top of it! Specifically, if I
> change the type signature of runArraysOf to
>
> runArraysOf
> :: (forall s1 s2.
> (forall x. MutableArray s1 x -> ST s2 (Array x)) -> t (mut s1 a) -> ST
s2 u)
> -> (forall s. ST s (t (mut s a)))
> -> u
>
> then I can write
>
> runHetArraysOf trav m = runArraysOf (\f -> trav f . unT) $ T <$> m
> newtype T (t :: (* -> *) -> *) (msa :: *) = T {unT :: t (Fun msa)}type
family Fun x where
> Fun (f x) = f
>
> —
> You are receiving this because you commented.
>
>
> Reply to this email directly, view it on GitHub
> <#109 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAAQwmpclIulqGPz_
AJ8czjZxoHIyoYaks5tqNuAgaJpZM4S6VN1>
> .
>
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#109 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABzi_fUI42nfH3yYqdhb4wxAHjEmQWpdks5tqPlOgaJpZM4S6VN1>
.
|
Let met take that back a bit... The ergonomics of the extreme class-based
version don't seem that great. Maybe I can fix that, but maybe not. The
array-type-specific versions, on the other hand, have great ergonomics, and
there doesn't seem to be anywhere more sensible to put them than here.
…On Thu, Apr 19, 2018 at 5:02 PM, David Feuer ***@***.***> wrote:
That might be reasonable. On the other hand, one of the versions I
described uses a Freezable class to be able to freeze anything with a
notion of freezing. That Freezable class, to be maximally useful, should
live at the lowest level of the module hierarchy that it can. Optimally,
that would probably mean GHC.Arr, but starting it somewhere in primitive
might be a good compromise. With that class available, anyone can write a
Trustworthy version of runArraysOf with their desired type details.
On Thu, Apr 19, 2018 at 4:53 PM, Carter Tazio Schonwald <
***@***.***> wrote:
> One thing I’ve been thinking about is maybe this set of combinators would
> make more sense to live in lens. A lot of the utility seems like it’d be
> highest for folks who use lense a lot. Especially the whole higher rank
> traversal bit.
>
> I guess what I mean is that comfort using these combinators seems
> predicated on using lens, which is down stream of primitive.
>
> At a philosophical level, my perspective on the primitive package is that
> it’s about making the various magic hash mutable data structures ghc
> provides usable from types in kind Star. Vector and similar higher level
> libraries are the clients / users of primitive for their data structure
> needs
>
>
> The only exception is We can’t do that safely for STM Data structures in
> primitive because of the no nesting transactions requirement of stm
> precluding execution in any setting / prim monad aside from those with io
> as the base monad.
>
> So I guess what I’m trying to say is that I’m currently inclined to say no
> to adding these traversal combinators to primitive. Though I’ll ponder
> this a bit more before I take a strong stance
>
> On Thu, Apr 19, 2018 at 2:46 PM David Feuer ***@***.***>
> wrote:
>
> > Aha! I just realized something. If I modify runArraysOf very slightly, I
> > can actually implement runHetArraysOf on top of it! Specifically, if I
> > change the type signature of runArraysOf to
> >
> > runArraysOf
> > :: (forall s1 s2.
> > (forall x. MutableArray s1 x -> ST s2 (Array x)) -> t (mut s1 a) -> ST
> s2 u)
> > -> (forall s. ST s (t (mut s a)))
> > -> u
> >
> > then I can write
> >
> > runHetArraysOf trav m = runArraysOf (\f -> trav f . unT) $ T <$> m
> > newtype T (t :: (* -> *) -> *) (msa :: *) = T {unT :: t (Fun msa)}type
> family Fun x where
> > Fun (f x) = f
> >
> > —
> > You are receiving this because you commented.
> >
> >
> > Reply to this email directly, view it on GitHub
> > <#109 (comment)>,
> > or mute the thread
> > <https://github.com/notifications/unsubscribe-auth/
> AAAQwmpclIulqGPz_AJ8czjZxoHIyoYaks5tqNuAgaJpZM4S6VN1>
>
> > .
> >
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <#109 (comment)>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/ABzi_fUI42nfH3yYqdhb4wxAHjEmQWpdks5tqPlOgaJpZM4S6VN1>
> .
>
|
In my mind,
My other concern is that we have the following implementations:
These two functions have identical implementations and slightly different type signatures. It bothers me that the type signatures of these two cannot somehow be unified, but there seems to be no way around this. Also, there's a annoying asymmetry going on. We don't have a |
These are valid points, but let’s make sure we don’t scope creep the role
of the primitive package :)
…On Fri, Apr 20, 2018 at 9:12 AM Andrew Martin ***@***.***> wrote:
In my mind, runArrays is clearly useful and should be included. I doubt
that I personally would ever remember to use anything beyond runArrays. I
would probably forget and just do it without the combinators. Here are my
general documentation-related concerns:
- What is a rank-2 traversal? Are there laws that such a function must
satisfy? A google search for "haskell rank 2 traversal" turns up nothing
relevant. The docs should probably link to resources or other haskell
libraries.
- An example of how to use runHetArraysOf is provided. This is good.
But, is this function intended to be used with functions from some other
library? Are the arguments taken in a particular order for a particular
reason? Is this intended to be used with lens or something like lens?
If so, it would be nice to include the lens-type-synonym translation of the
type signature in the docs.
My other concern is that we have the following implementations:
runArraysOf trav m = runST $ m >>= trav unsafeFreezeArray
runHetArraysOf trav m = runST $ m >>= trav unsafeFreezeArray
These two functions have identical implementations and slightly different
type signatures. It bothers me that the type signatures of these two cannot
somehow be unified, but there seems to be no way around this.
Also, there's a annoying asymmetry going on. We don't have a runHetArrays
function (with a TraversableRank2 typeclass constraint or whatever the
appropriate typeclass is named). This makes me more inclined to say that
runHetArraysOf belongs in some other package, but it does seem to be
pretty useful in the example given, so I guess I like it here.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#109 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAAQwuB7HFEjnTyleLuzQOrcwBi-ceP3ks5tqd61gaJpZM4S6VN1>
.
|
Create arbitrarily many arrays of arbitrarily many types from one
ST
action.Closes #103