Is there a typeclass for references similar to the MArray class for mutable arrays? - haskell

The MArray class provides generic functions for working with mutable arrays of various sorts in both ST and IO contexts. I haven't been able to find a similar class for working with both STRefs and IORefs. Does such a thing exist?

The ref-fd package provides it:
class Monad m => MonadRef r m | m -> r where
[...]
or with type families, ref-tf:
class Monad m => MonadRef m where
type Ref m :: * -> *
[...]
Another answer suggested the monad-statevar package which doesn't have the functional dependency. It also has separate HasGet and HasPut members and no abstraction over the newRef functionality.
Aside from the different methods in each, the functional dependency is a design trade-off. Consider the following two simplified classes:
class MRef1 r m where
newRef1 :: a -> m (r a)
readRef1 :: r a -> m a
class MRef2 r m | m -> r where
newRef2 :: a -> m (r a)
readRef2 :: r a -> m a
With MRef1, both the monad type and the reference type can vary freely, so the following code has a type error:
useMRef1 :: ST s Int
useMRef1 = do
r <- newRef1 5
readRef1 r
No instance for (MRef1 r0 (ST s)) arising from a use of `newRef1'
The type variable `r0' is ambiguous
We have to add an extra type signature somewhere to say that we want to use STRef.
In contrast, the same code works fine for MRef2 without any extra signature. The signature on the definition saying that the whole code has type ST s Int, combined with the functional dependency m -> r means that there is only one r type for a given m type and so the compiler knows that our existing instance is the only possible one and we must want to use STRef.
On the flip side, suppose we want to make a new kind of reference, e.g. STRefHistory that tracks all the values that have ever been stored in it:
newtype STRefHistory s a = STRefHistory (STRef s [a])
The MRef1 instance is fine because we are allowed multiple reference types for the same monad type:
instance MRef1 (STRefHistory s) (ST s) where
newRef1 a = STRefHistory <$> newSTRef [a]
readRef1 (STRefHistory r) = head <$> readSTRef r
but the equivalent MRef2 instance fails with:
Functional dependencies conflict between instance declarations:
instance MRef2 (STRef s) (ST s) -- Defined at mref.hs:28:10
instance MRef2 (STRefHistory s) (ST s) -- Defined at mref.hs:43:10
I also mentioned the type family version, which is quite similar in expressive power to the functional dependency; the reference type is a "type function" of the monad type so there can again only be one per monad. The syntax ends up being a bit different and in particular you can just say MonadRef m in constraints, without stating what the reference type is within the constraint.
It's also plausible to have the reversed functional dependency:
class MRef2 r m | r -> m where
so that each reference type can live in just one monad, but you can still have several reference types for a monad. Then you'd need type signatures on your references but not on your monadic computations as a whole.

Control.Monad.StateVar has a typeclass which lets you get and put IORefs and STRefs identically.

Related

Would it be possible to derive Data.Vector.Unbox via GHC's generic deriving?

It's possible to derive Storable via GHC's generic deriving mechanism: http://hackage.haskell.org/package/derive-storable (and https://hackage.haskell.org/package/derive-storable-plugin for performance). The only library I can find for deriving Data.Vector.Unbox, however, uses template Haskell: http://hackage.haskell.org/package/vector-th-unbox. It also requires the user to write a little code; it's not entirely automatic.
My question is, could a library like deriving-storable also exist for Unbox, or is this not possible due to some fundamental way in which Unbox differs from Storable? If the latter, does that mean it's also not possible to create a library that allows automatically deriving Unbox for any Storable type, as I could not find such a library.
I ask because ideally I'd like to avoid template Haskell and the manual annotations necessary for using vector-th-unbox.
Say we had some Generic_ class to convert between our own types and some uniform representation which happens to have an Unbox instance (which amounts to both MVector and Vector instances for the Unboxed variants):
class Generic_ a where
type Rep_ (a :: Type) :: Type
to_ :: a -> Rep_ a
from_ :: Rep_ a -> a
Then we can use that to obtain generic implementations of the methods of MVector/Vector:
-- (auxiliary definitions of CMV and uncoercemv at the end of this block)
-- vector imports (see gist at the end for a compilable sample)
import qualified Data.Vector.Unboxed as U
import qualified Data.Vector.Unboxed.Mutable as UM
import Data.Vector.Generic.Mutable.Base (MVector(..))
-- MVector
gbasicLength :: forall a s. CMV s a => UM.MVector s a -> Int
gbasicLength = basicLength #UM.MVector #(Rep_ a) #s . coerce
gbasicUnsafeSlice :: forall a s. CMV s a => Int -> Int -> UM.MVector s a -> UM.MVector s a
gbasicUnsafeSlice i j = uncoercemv . basicUnsafeSlice #UM.MVector #(Rep_ a) #s i j . coerce
-- etc.
-- idem Vector
-- This constraints holds when the UM.MVector data instance of a is
-- representationally equivalent to the data instance of its generic
-- representation (Rep_ a).
type CMV s a = (Coercible (UM.MVector s a) (UM.MVector s (Rep_ a)), MVector UM.MVector (Rep_ a))
-- Sadly coerce doesn't seem to want to solve this correctly so we use
-- unsafeCoerce as a workaround.
uncoercemv :: CMV s a => UM.MVector s (Rep_ a) -> UM.MVector s a
uncoercemv = unsafeCoerce
Now if we have some generic type
data MyType = MyCons Int Bool ()
We can define a generic instance with its isomorphism to a tuple
instance Generic_ MyType where
type Rep_ MyType = (Int, Bool, ())
to_ (MyCons a b c) = (a, b, c)
from_ (a, b, c) = MyCons a b c
And from there, there is a totally generic recipe to get its Unbox instance, if you have YourType instead with its own Generic_ instance, you can take this and literally replace MyType with YourType.
newtype instance UM.MVector s MyType
= MVMyType { unMVMyType :: UM.MVector s (Rep_ MyType) }
instance MVector UM.MVector MyType where
basicLength = gbasicLength
basicUnsafeSlice = gbasicUnsafeSlice
-- etc.
-- idem (Vector U.Vector MyType)
-- MVector U.Vector & Vector UM.MVector = Unbox
instance Unbox MyType
In theory all this boilerplate could be automated with internal language features (as opposed to TemplateHaskell or CPP). But there are various issues that get in the way in the current state of things.
First, Generic_ is essentially Generic from GHC.Generics. However, the uniform representation that gets derived by GHC is not in terms of tuples (,) but in terms of somewhat ad-hoc type constructors (:+:, :*:, M1, etc.), which lack Unbox instances.
Such Unbox instances could be added to use Generic directly
the generics-eot has a variant of Generic relying on tuples that could be a direct replacement to Generic_ here.
And second, MVector and Vector have quite a few methods. To avoid having to list them all, one might expect to leverage DerivingVia (or GeneralizedNewtypeDeriving), however they are not applicable because there are a couple of polymorphic monadic methods that prevent coercions (e.g., basicUnsafeNew). For now, the easiest way I can think of to abstract this is a CPP macro. In fact the vector package uses that technique internally, and it might be reusable somehow. I believe properly addressing those issues requires a deep redesign of the Vector/MVector architecture.
Gist (not complete, but compilable): https://gist.github.com/Lysxia/c7bdcbba548ee019bf6b3f1e388bd660

Haskell class definition question about restrictions

class IndexSelect k (m :: k -> (* -> *) -> *) | m -> k where
type Restriction m (p :: k) :: Constraint
indexSelect :: Restriction m p => Sing (p :: k) -> Proxy m -> LocalDb f -> f (TableEntity (m p))
I'm new to the Haskell language. I'm having trouble deciphering the class definition in some code in the code repo at the company I just started at.
What is this doing?
There is a lot going on here. I am going to start by referring you to Sections 7.6 Class and Instance Declarations, 7.7 Type Families, and 7.8.4 Explicitly-kinded qualifications of the GHC language extension documentation. (I am by no means an expert on any of these and clicked on your question hoping someone had supplied further enlightenment.)
We are defining a multi-parameter type class called IndexSelect with parameters k and m. (Multi-parameter type classes 7.6.1.1)
The second parameter of the class, m, is given an explicit kind qualification: k -> (* -> *) -> * in English m must be a function which takes a k and a function and returns a value. (7.8.4 Explicitly-kinded quantification)
The class has a functional dependency | m -> k. Where the choice of m must uniquely determine k Given the name of this function that implies that a collection m must have only one kind of key k which is reasonable. (7.6.2 Functional Dependencies)
The class forms a indexed type family type Restriction m (p :: k) :: Constraint. It appears inside a class definition so it is an associated type synonym. (7.7.2.1.1 Associated type family declarations). It takes some m and a p which must be of type k and results in a Constraint.
The class has one listed method indexSelect which one might guess manages to extract information from a collection. Without knowing what Sing, LocalDb and TableEntity do I cannot say more.

How to abstract over monads without fighting the type system in Haskell?

I'm currently building a server in haskell and as a newbie to the language, I'd like to try a new approach zu Monad composition. The idea is that we can write library methods like
isGetRequest :: (SupportsRequests m r) => m Bool
isGetRequest = do
method <- liftRequests $ requestMethod
return $ method == GET
class (Monad m, RequestSupport r) => SupportsRequests m r | m -> r where
liftRequests :: r a -> m a
class (Monad r) => RequestSupport r where
requestMethod :: r Method
which work without knowing the underlying monad. Of course in this example, it would have been sufficient to make isGetRequest operate directly on the (RequestSupport r) monad but the idea is that my library might also have more than one constraint on the monad. Yet, I do not want to implement all of those different concerns in the same module nor spread them across different modules (orphan instances!).
That's why the m monad only implements the Supports* classes, delegating the real concerns to other monads.
The above code should work perfectly (with some language extensions to GHC). Unfortunately, I got some problems with the CRUD (Create Read Update Delete) concern:
class (Monad m, CRUDSupport c a) => SupportsCRUD m c a | m a -> c where
liftCRUD :: c x -> m x
class (Monad c) => CRUDSupport c a | c -> a where
list :: c [a] -- List all entities of type a
No I get an error:
Could not deduce (SupportsCRUD m c a0) from the context [...]
The type variable 'a0' is ambiguous [...]
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method: liftCRUD [...]
Seems like the type checker doesn't like that the a parameter does not directly arise in the signature of liftCRUD. That's understandable because a cannot be derived from the functional dependencies.
The type checker in my brain tells me that it should not be a problem to infer the type a later on, using AllowAmbiguousTypes, when some method regarding CRUD is executed in a library method. Unfortunately, GHC seems unable to do this inference step, for example
bookAvailable :: (SupportsCRUD m c Book) => m Bool
bookAvailable = do
books <- liftCRUD (list :: c [Book]) -- I use ScopedTypeVariables
case books of
[] -> return False
_ -> return True
yields
Could not deduce (SupportsCRUD m c0 a1) arising from a use of 'liftCRUD' [...]
The type variables c0, a1 are ambiguous [...]
It seems that I am still unable to reason about the compiler. I there a way to resolve this problem? Or at least a way to understand what the compiler is able to infer?
Best Regards,
bloxx
To use ScopedTypeVariables you also need to bind the variables you want to be in scope with forall. So it should be
bookAvailable :: forall m c. (SupportsCRUD m c Book) => m Bool
...
That was all that was necessary (after some trivial fixes I made which I assume were typos from entering your question) for me to get the code to compile.

Type variable is not in scope when defining type class

I'm writing a type class à la mtl-style transformers. Looks like this:
class (Monad m, Stream s m t) => MonadStuff s m | m -> s where
-- function signatures go here…
I'm trying to say by that that m should be instance of Monad and there
should be instance of Stream s m t, where t doesn't really matter but
s and m are from the right side of the definition (after =>).
Haskell says:
Not in scope: type variable ‘t’
So, obviously I cannot do that. Or can I? Should I remove Stream s m t
constraint and add it to every function in the class instead or is there
another way?
If it's really true that it doesn't really matter what t is, then perhaps you can ask the person writing the instance to choose it:
{-# LANGUAGE TypeFamilies #-}
class (Monad m, Stream s m (StuffType m)) => MonadStuff s m | m -> s where
type StuffType m
Or, since you already have MPTCs and fundeps turned on, you could consider doing this, which requires no extra extensions but is otherwise basically identical:
class (Monad m, Stream s m t) => MonadStuff s m t | m -> s t where
However, I am suspicious that in fact the choice of t does matter: unless Stream has a fundep that is at least as informative as m s -> t, you will not be able to use this constraint in a meaningful way. In that case, you should move the constraint into the signatures of the methods that mention t or will be using the Stream methods.

Defining a MonadEither type class

I'm going back through Monad Transformers : Step by Step as a refresher, and like many tutorials out there, it uses Control.Monad.Error. GHC now gives a warning that this module is deprecated, so I switched over to Control.Monad.Trans.Either from the either library: http://hackage.haskell.org/package/either-3.4/docs/Control-Monad-Trans-Either.html
Everything is handled smoothly with eval2 in the paper, since EitherT is the outermost monad. However, after that everything falls apart -- ReaderT is in no way an Either value, and everything henceforth uses ErrorT, which I'd like to change to EitherT.
My idea, then, was to define a MonadEither type class that boxed left and right in order to handle errors, but this hasn't been fruitful. I don't really understand how the type classes in mtl work, and this instance in particular has to be parameterized over multiple values, which is confusing. I came up with the following, which compiles after including some syntactic extensions:
class (Monad m) => MonadEither l r m | m -> r where
right :: r -> m r
left :: l -> m r
But I can't figure out a MonadEither instance of EitherT:
instance Monad m => MonadEither l r (E.EitherT l m) where
right = E.right
left = E.left
Edit: I changed the instance declaration to match E.EitherT properly, and get the following error message:
Illegal instance declaration for ‘MonadEither l r (E.EitherT l m)’
The coverage condition fails in class ‘MonadEither’
for functional dependency: ‘m -> r’
Reason: lhs type ‘E.EitherT l m’ does not determine rhs type ‘r’
In the instance declaration for ‘MonadEither l r (E.EitherT l m)’
Again, I'm not really sure what I'm doing. I don't really understand functional dependencies, so I'm just looking for some guidance as to what an appropriate MonadEither type class might look like, if possible to define.
How about
instance Monad m => MonadEither l r (E.EitherT l m)
That is, it should be l instead of r.
However once you've done this you'll come up across a separate error. The root cause is that there's no point to right; it's just return. This means you need to get rid of the r parameter to the class.
class Monad m => MonadEither l m where
left :: l -> m a
Your instance declaration should then become
instance Monad m => MonadEither l (E.EitherT l m)
(You also may want to look at the MonadError class since this is essentially what you are replicating.)

Resources