Automatic output of Data.Vector.Unbox with associated type synonyms

I have a data type

newtype Zq q = Zq (IntType q) 

where 'q' will be an instance of the class

 class Foo a where type IntType a 

and 'IntType' is just the base view (i.e., Int, Integral, etc.) associated with q.

I want to make Zq an instance of Data.Vector.Unbox . Currently, we manually output Unbox using about 50 lines of trivial code, as suggested in the link above. We will do several different types of "Unbox" in our code, so writing 50 lines for each type is not attractive.

I found two alternatives here . One option is to use this package , which uses Template Haskell to output Unbox instances. The TH code would look like this:

 derivingUnbox "Zq" [d| instance (Foo q, U.Unbox (IntType q)) => Unbox' (ZqBasic q) (IntType q) |] [| \ (Zq x) -> x |] [| \ x -> Zq x |] 

The problem is that I cannot define instances using the associated type synonyms (or can I?)

[Related question: Why TypeSynonymInstances , an extension implied by FlexibleInstances, does not allow instances of a type synonym related ? Is this somehow a fundamentally different beast?]

My current solution to this problem is to redefine Zq as

 newtype Zq qi = Zq i 

and then add an equality constraint

 i~(IntType q) 

in each case, including (Zq qi), which is not very elegant. My (working) Unbox output becomes

 derivingUnbox "Zq" [d| instance (U.Unbox i, i~IntType q, Foo q) => Unbox' (Zq qi) i |] [| \ (Zq x) -> x |] [| \ x -> Zq x |] 

It seems to me that I could accomplish this without resorting to explicit exposures of the "i" type. All I did is transfer it from the associated type synonym to an explicit parameter with equality constraints. Why is this β€œfundamentally” different (and, apparently, safer)? Is there a way to avoid adding a parameter of type β€œi” and still get automatic Unbox output?

Optional parameter parameter, I am having problems using the TH package to display Unbox for (Vector r), that is, I want to make Unbox Vector of Unbox Vectors. My attempt is something like:

 newtype Bar r = Bar (Vector r) derivingUnbox "Bar" [d| instance (Unbox r) => Unbox' (Bar r) (Vector r) |] [| \ (Bar x) -> x |] [| \ x -> Bar x |] 

but I get (many) errors, for example:

 `basicUnsafeFreeze` is not a (visible) method of class `Data.Vector.Generic.Base.Vector` 

I'm not sure why he cannot find this method when it works great for my Zq type.


The following approach, described above, uses the GeneralizedNewtypeDeriving extension. The biggest problem that I see with this approach is that I have some factual data (not Newtype) that I need for Unbox. However, just using the extension, I should be able to write

 newtype Zq q = Zq (IntType q) deriving (Unbox, M.MVector MVector, G.Vector Vector) 

or at least

 newtype Zq qi = Zq i deriving (Unbox, M.MVector MVector, G.Vector Vector) 

The first leads to errors:

 No instance for (Unbox (IntType q)) arising from the `deriving` clause of a data type declaration No instance for (M.MVector MVector (IntType q)) "" No instance for (G.Vector Vector (IntType q)) "" 

and the second gives:

 No instance for (M.MVector MVector i) "" No instance for (G.Vector U.Vector i) "" 

I'm not sure why he cannot get these instances, as the above post makes me believe that he should be capable. Maybe I can use the associated type synonym with GeneralizedNewtypeDeriving? (This still (maybe) does not solve my problem when I need to get Unbox for "data".)

Thanks for your help!

+6
source share
2 answers

Here you are faced with several separate problems:

TH approach

Yes, instance instances for associated synonym types are illegal

It is true that you cannot define instance instances for related type synonyms or type functions, and this is not without reason: the compiler cannot determine whether they overlap. For instance:

 type family F a instance Eq (F Int) instance Eq (F Bool) 

Are these instances related? Given the source code above, we cannot say: it depends on how someone later defines the instances for F For example, they could identify

 type instance F Int = Double type instance F Bool = Double 

and then the two instances of Eq will actually overlap.

You have a problem with the vector-th-unbox

If you look at the actual Unbox instance that you need, you really don't need the instance for IntType q ; you want just:

 instance (Unbox (IntType q), Foo q) => Unbox (Zq q) where ... 

The problem is that the vector-th-unbox forces you to use the fake Unbox' type class to Unbox' intermediate view type ( IntType q in your case), as a convenient way to abuse the Haskell template syntax in the type. And then the GHC sees that you wrote Unbox' (Zq q) (IntType q) and complain. I suggest giving an error for the vector-th-unbox .

Unbox for Vector r

I think Louis Wasserman covered this.

GeneralizedNewtypeDeriving Approach

A specific compilation error is that the GHC cannot output the appropriate context. For most problems, similar to those you have, the StandaloneDeriving extension will solve your problem:

 deriving instance Unbox (IntType q) => Unbox (Zq q) deriving instance Unbox (IntType q) => M.MVector MVector (Zq q) deriving instance Unbox (IntType q) => G.Vector Vector (Zq q) 

But DO NOT do this!

Although GeneralizedNewtypeDeriving often does exactly what you want, it breaks down into some basic ways , and the Unbox instance that it produces is completely broken ! Therefore, follow the TH approach, after lobbying Liyang to fix your current problem.

+3
source

I changed the syntax in 4820b73 so that you can do what you want now:

 derivingUnbox "Complex" [d| (Unbox a) β‡’ Complex a β†’ (a, a) |] [| \ (r :+ i) β†’ (r, i) |] [| \ (r, i) β†’ r :+ i |] 

I also fixed the "xyz not method (visible) ..." error in fe37976 , although it was possible to get around it with:

 import qualified Data.Vector.Generic import qualified Data.Vector.Generic.Mutable 

You are now on Hackage . CC: @reinerp

+4
source

Source: https://habr.com/ru/post/920050/


All Articles