suggestion: A common type class for mutable variables
Dear Haskellers, I noticed that there is no common typeclass that would unify STRefs and IORefs. We already have MArray for ST(U)Arrays and IO(U)Arrays, so why not for references as well? This would allow writing generic code that can use both ST- and IO-based variables. I've found that there is a package that provides such a type class: http://hackage.haskell.org/package/reference I'd suggest to add similar functionality to base, perhaps with some different wording - I'd rather use Data.MRef (as "mutable reference"). If there is some interest in it, I'd prepare a concrete code for consideration. Best regards, Petr Pudlak
On Thu, 30 May 2013, Petr Pudlák wrote:
I've found that there is a package that provides such a type class: http://hackage.haskell.org/package/reference
I'd suggest to add similar functionality to base, perhaps with some different wording - I'd rather use Data.MRef (as "mutable reference").
There are more such packages: http://hackage.haskell.org/package/stateref http://hackage.haskell.org/package/monad-statevar http://hackage.haskell.org/package/ref-fd http://hackage.haskell.org/package/ref-tf http://hackage.haskell.org/package/ref-mtl
On Mon, 3 Jun 2013, harry wrote:
another one:
http://hackage.haskell.org/packages/archive/binding-core/latest/doc/html/Dat...
And yet another one: http://hackage.haskell.org/packages/archive/ArrayRef/0.1.3.1/doc/html/Data-R... I have started a Wiki page in order to keep an overview of all the existing approaches: http://www.haskell.org/haskellwiki/Mutable_variable
Henning Thielemann <lemming <at> henning-thielemann.de> writes:
I have started a Wiki page in order to keep an overview of all the existing approaches: http://www.haskell.org/haskellwiki/Mutable_variable
There seems to be a fair amount of duplication in all this ... any idea how a "standard" approach could be selected?
I see little hope in standardizing as, heck, I personally have felt the need to use two of the different points in the design space within just my own code. -Edward On Mon, Jun 3, 2013 at 2:13 PM, harry <voldermort@hotmail.com> wrote:
Henning Thielemann <lemming <at> henning-thielemann.de> writes:
I have started a Wiki page in order to keep an overview of all the existing approaches: http://www.haskell.org/haskellwiki/Mutable_variable
There seems to be a fair amount of duplication in all this ... any idea how a "standard" approach could be selected?
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Could you please just shortly comment about those two? I'd be interested to know. Thanks, Petr Dne 06/03/2013 08:32 PM, Edward Kmett napsal(a):
I see little hope in standardizing as, heck, I personally have felt the need to use two of the different points in the design space within just my own code.
-Edward
On Mon, Jun 3, 2013 at 2:13 PM, harry <voldermort@hotmail.com> wrote:
Henning Thielemann <lemming <at> henning-thielemann.de> writes:
I have started a Wiki page in order to keep an overview of all the existing approaches: http://www.haskell.org/haskellwiki/Mutable_variable There seems to be a fair amount of duplication in all this ... any idea how a "standard" approach could be selected?
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
The first option is class Monad m => MonadRef r m | m -> r where newRef :: a -> m (r a) ... This has the benefit of using quite portable extensions. The second option is class Monad m => MonadRef m where type Ref m :: * -> * newRef :: a -> m (Ref m a) This takes us into GHC specific territory, by using type families, but avoids polluting every type that uses one with an extra 'ref' param. I use this variant in my as-yet-unreleased 'revisions' package. Both of these have the benefit that they can work with transformers, but they carry the limitation that you can't have multiple reference types for the same monad. e.g. you can't use the same combinators for both IORefs and, say, MVars or TVars within the same monad. This is arguably not so much a problem as they have very different operational semantics! In other code I've done horrible things for lifting TVars out into monad transformer stacks, while well aware of the rather ad hoc meaning of chains of operations on TVars when you are working over something IO based. Peeking at some haddocks from my analytics project: class Monad<http://rebase.org/Library/Frameworks/GHC.framework/Versions/7.4.1-x86_64/usr/share/doc/ghc/html/libraries/base-4.5.0.0/Control-Monad.html#t:Monad> m => MonadSTM m whereSource<http://rebase.org/analytics/src/Data-Analytics-Task-STM.html#MonadSTM> stm :: STM<http://rebase.org/Library/Frameworks/GHC.framework/Versions/7.4.1-x86_64/usr/share/doc/ghc/html/libraries/base-4.5.0.0/GHC-Conc.html#t:STM> a -> m aSource<http://rebase.org/analytics/src/Data-Analytics-Task-STM.html#stm> newTV :: a -> m (TVar<http://rebase.org/Library/Frameworks/GHC.framework/Versions/7.4.1-x86_64/usr/share/doc/ghc/html/libraries/base-4.5.0.0/GHC-Conc.html#t:TVar> a)Source<http://rebase.org/analytics/src/Data-Analytics-Task-STM.html#newTV> readTV :: TVar<http://rebase.org/Library/Frameworks/GHC.framework/Versions/7.4.1-x86_64/usr/share/doc/ghc/html/libraries/base-4.5.0.0/GHC-Conc.html#t:TVar> a -> m aSource<http://rebase.org/analytics/src/Data-Analytics-Task-STM.html#readTV> newTMV :: a -> m (TMVar<http://rebase.org/Library/Haskell/ghc-7.4.1/lib/stm-2.3/doc/html/Control-Concurrent-STM-TMVar.html#t:TMVar> a)Source<http://rebase.org/analytics/src/Data-Analytics-Task-STM.html#newTMV> newEmptyTMV :: m (TMVar<http://rebase.org/Library/Haskell/ghc-7.4.1/lib/stm-2.3/doc/html/Control-Concurrent-STM-TMVar.html#t:TMVar> a)Source<http://rebase.org/analytics/src/Data-Analytics-Task-STM.html#newEmptyTMV> newTC :: m (TChan<http://rebase.org/Library/Haskell/ghc-7.4.1/lib/stm-2.3/doc/html/Control-Concurrent-STM-TChan.html#t:TChan> a) This had the benefit of staying in 98 style, but solved a different problem than what we're discussing here, because the reference type was fixed. In yet other code i've had the reference type select the monad it works with. The primitive package that is used by vector is at least morally of this flavor, though, for array types rather than references, but another example is the 'var' package that was released the other day in response to this thread. It doesn't use any functional dependencies between the monad and the reference type in order to support multiple reference types per monad, including unboxed variants. -Edward On Mon, Jun 3, 2013 at 2:38 PM, Petr Pudlák <petr.mvd@gmail.com> wrote:
Could you please just shortly comment about those two? I'd be interested to know.
Thanks, Petr
Dne 06/03/2013 08:32 PM, Edward Kmett napsal(a):
I see little hope in standardizing as, heck, I personally have felt the need to use two of the different points in the design space within just my own code.
-Edward
On Mon, Jun 3, 2013 at 2:13 PM, harry <voldermort@hotmail.com> <voldermort@hotmail.com> wrote:
Henning Thielemann <lemming <at> henning-thielemann.de> writes:
I have started a Wiki page in order to keep an overview of all the existing approaches: http://www.haskell.org/haskellwiki/Mutable_variable
There seems to be a fair amount of duplication in all this ... any idea how a "standard" approach could be selected?
_______________________________________________ Libraries mailing listLibraries@haskell.orghttp://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing listLibraries@haskell.orghttp://www.haskell.org/mailman/listinfo/libraries
On Mon, 3 Jun 2013, Edward Kmett wrote:
The first option is
class Monad m => MonadRef r m | m -> r where newRef :: a -> m (r a) ...
This has the benefit of using quite portable extensions.
The second option is
class Monad m => MonadRef m where type Ref m :: * -> * newRef :: a -> m (Ref m a) This takes us into GHC specific territory, by using type families, but avoids polluting every type that uses one with an extra 'ref' param. I use this variant in my as-yet-unreleased 'revisions' package.
Both of these have the benefit that they can work with transformers, but they carry the limitation that you can't have multiple reference types for the same monad. e.g. you can't use the same combinators for both IORefs and, say, MVars or TVars within the same monad. This is arguably not so much a problem as they have very different operational semantics!
I thought the functional dependency should be the other way round: From the reference type to the monad where it lives in.
Dne 06/03/2013 09:11 PM, Henning Thielemann napsal(a):
On Mon, 3 Jun 2013, Edward Kmett wrote:
The first option is
class Monad m => MonadRef r m | m -> r where newRef :: a -> m (r a) ...
This has the benefit of using quite portable extensions.
The second option is
class Monad m => MonadRef m where type Ref m :: * -> * newRef :: a -> m (Ref m a)
This takes us into GHC specific territory, by using type families, but avoids polluting every type that uses one with an extra 'ref' param. I use this variant in my as-yet-unreleased 'revisions' package.
Both of these have the benefit that they can work with transformers, but they carry the limitation that you can't have multiple reference types for the same monad. e.g. you can't use the same combinators for both IORefs and, say, MVars or TVars within the same monad. This is arguably not so much a problem as they have very different operational semantics!
I thought the functional dependency should be the other way round: From the reference type to the monad where it lives in.
For monads, it's (AFAIK) always this way, because |m| is always in the result, but not necessarily the other type. Let's consider |readRef :: r a -> m a| In order to type-check |x| in |readRef x|, we need to determine |r a| from |m a|, so the dependency must be |m -> r|.
The inference can flow in either direction here. Haskell has no issue with inferring the type of an input to a function based on the type of the result. Type classes are pretty magical in that regard. On Mon, Jun 3, 2013 at 3:22 PM, Petr Pudlák <petr.mvd@gmail.com> wrote:
Dne 06/03/2013 09:11 PM, Henning Thielemann napsal(a):
On Mon, 3 Jun 2013, Edward Kmett wrote:
The first option is
class Monad m => MonadRef r m | m -> r where newRef :: a -> m (r a) ...
This has the benefit of using quite portable extensions.
The second option is
class Monad m => MonadRef m where type Ref m :: * -> * newRef :: a -> m (Ref m a)
This takes us into GHC specific territory, by using type families, but avoids polluting every type that uses one with an extra 'ref' param. I use this variant in my as-yet-unreleased 'revisions' package.
Both of these have the benefit that they can work with transformers, but they carry the limitation that you can't have multiple reference types for the same monad. e.g. you can't use the same combinators for both IORefs and, say, MVars or TVars within the same monad. This is arguably not so much a problem as they have very different operational semantics!
I thought the functional dependency should be the other way round: From the reference type to the monad where it lives in.
For monads, it's (AFAIK) always this way, because m is always in the result, but not necessarily the other type. Let's consider
readRef :: r a -> m a
In order to type-check x in readRef x, we need to determine r a from m a, so the dependency must be m -> r.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
That was the last variant I mentioned in that post. The complication that introduces is that you then can't auto-lift newRef, etc. into transformer stacks. -Edward On Mon, Jun 3, 2013 at 3:11 PM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Mon, 3 Jun 2013, Edward Kmett wrote:
The first option is
class Monad m => MonadRef r m | m -> r where newRef :: a -> m (r a) ...
This has the benefit of using quite portable extensions.
The second option is
class Monad m => MonadRef m where type Ref m :: * -> * newRef :: a -> m (Ref m a)
This takes us into GHC specific territory, by using type families, but avoids polluting every type that uses one with an extra 'ref' param. I use this variant in my as-yet-unreleased 'revisions' package.
Both of these have the benefit that they can work with transformers, but they carry the limitation that you can't have multiple reference types for the same monad. e.g. you can't use the same combinators for both IORefs and, say, MVars or TVars within the same monad. This is arguably not so much a problem as they have very different operational semantics!
I thought the functional dependency should be the other way round: From the reference type to the monad where it lives in.
Henning Thielemann wrote:
On Mon, 3 Jun 2013, Edward Kmett wrote:
The first option is
class Monad m => MonadRef r m | m -> r where newRef :: a -> m (r a) ...
I thought the functional dependency should be the other way round: From the reference type to the monad where it lives in.
You can have it both ways. class Monad m => RefM m r | m -> r, r -> m where -- | Create a new reference. newRef :: a -> m (r a) [...] Cheers, Bertram
There are no MPTCs or type families in base outside of the GHC.* at this time and there are several libraries that provide this functionality as a layer on top. I don't really see the need to bless one over the rest by folding it into base, as there are several points in the design space available and each is better for different audiences. MPTCs+FD for portability, MPTCs+TFs for GHC-specifics, even MPTCs without either or with the FD running the other direction, to permit the combinatory to work on more ref types in exchange for worse inference. In fact there is a strong case against including it in base: If the FD or TF went from the monad to the ref type, then you'd want it to auto lift over transformers without orphan instances, but this would require transformers to break Haskell 98/2010, which isn't palatable given transformers' stated goals! The requisite layering is better served (and only possible) by this being a non-base package, which is precisely the status quo. -1 -Edward On May 30, 2013, at 2:53 PM, Petr Pudlák <petr.mvd@gmail.com> wrote:
Dear Haskellers,
I noticed that there is no common typeclass that would unify STRefs and IORefs. We already have MArray for ST(U)Arrays and IO(U)Arrays, so why not for references as well? This would allow writing generic code that can use both ST- and IO-based variables.
I've found that there is a package that provides such a type class: http://hackage.haskell.org/package/reference I'd suggest to add similar functionality to base, perhaps with some different wording - I'd rather use Data.MRef (as "mutable reference").
If there is some interest in it, I'd prepare a concrete code for consideration.
Best regards, Petr Pudlak
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
OK, I didn't know about the variety of available packages, and I didn't realize that this would introduce new language extensions into base. I got carried away by the parallel with MArray, which is actually in a separate package. I retract the suggestion. Best regards, Petr Čt 30. květen 2013, 22:59:21 CEST, Edward Kmett napsal:
There are no MPTCs or type families in base outside of the GHC.* at this time and there are several libraries that provide this functionality as a layer on top.
I don't really see the need to bless one over the rest by folding it into base, as there are several points in the design space available and each is better for different audiences. MPTCs+FD for portability, MPTCs+TFs for GHC-specifics, even MPTCs without either or with the FD running the other direction, to permit the combinatory to work on more ref types in exchange for worse inference.
In fact there is a strong case against including it in base:
If the FD or TF went from the monad to the ref type, then you'd want it to auto lift over transformers without orphan instances, but this would require transformers to break Haskell 98/2010, which isn't palatable given transformers' stated goals!
The requisite layering is better served (and only possible) by this being a non-base package, which is precisely the status quo.
-1
-Edward
On May 30, 2013, at 2:53 PM, Petr Pudlák <petr.mvd@gmail.com> wrote:
Dear Haskellers,
I noticed that there is no common typeclass that would unify STRefs and IORefs. We already have MArray for ST(U)Arrays and IO(U)Arrays, so why not for references as well? This would allow writing generic code that can use both ST- and IO-based variables.
I've found that there is a package that provides such a type class: http://hackage.haskell.org/package/reference I'd suggest to add similar functionality to base, perhaps with some different wording - I'd rather use Data.MRef (as "mutable reference").
If there is some interest in it, I'd prepare a concrete code for consideration.
Best regards, Petr Pudlak
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
Perhaps it's worth pointing out that one can avoid the functional dependencies (not the MPTCs) with a common API based on an explicit state dictionary: see code below. I would also personally find such an API more elegant, but I'm not sure others would agree with this. There is also an advantage that StateD is also usable with the state monad and monad transformer (see function stateD below). I'm not sure whether this idea has been tried out in practice yet. Regards, Dominique module Ref where import Data.IORef import Data.STRef import Control.Monad.ST import Control.Applicative import Control.Monad.State data StateD s m = StateD { putM :: s -> m (), getM :: m s } class MutRef m where newRef :: s -> m (StateD s m) ioRefStateD :: IORef a -> StateD a IO ioRefStateD r = StateD (writeIORef r) (readIORef r) instance MutRef IO where newRef v = ioRefStateD <$> newIORef v stRefStateD :: STRef s a -> StateD a (ST s) stRefStateD r = StateD (writeSTRef r) (readSTRef r) instance MutRef (ST s) where newRef v = stRefStateD <$> newSTRef v stateD :: MonadState s m => StateD s m stateD = StateD put get 2013/5/30 Petr Pudlák <petr.mvd@gmail.com>:
Dear Haskellers,
I noticed that there is no common typeclass that would unify STRefs and IORefs. We already have MArray for ST(U)Arrays and IO(U)Arrays, so why not for references as well? This would allow writing generic code that can use both ST- and IO-based variables.
I've found that there is a package that provides such a type class: http://hackage.haskell.org/package/reference I'd suggest to add similar functionality to base, perhaps with some different wording - I'd rather use Data.MRef (as "mutable reference").
If there is some interest in it, I'd prepare a concrete code for consideration.
Best regards, Petr Pudlak
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
On Sun, 9 Jun 2013, Dominique Devriese wrote:
Perhaps it's worth pointing out that one can avoid the functional dependencies (not the MPTCs) with a common API based on an explicit state dictionary: see code below. I would also personally find such an API more elegant, but I'm not sure others would agree with this.
It's nice! And you need the multi-parameter type class only if you want to use the MonadState class.
2013/6/9 Dominique Devriese <dominique.devriese@cs.kuleuven.be>:
Perhaps it's worth pointing out that one can avoid the functional dependencies (not the MPTCs) with a common API based on an explicit state dictionary
Hm, on second look, it seems to avoid MPTCs as well... Regards, Dominique
participants (6)
-
Bertram Felgenhauer -
Dominique Devriese -
Edward Kmett -
harry -
Henning Thielemann -
Petr Pudlák