Using Template Haskell to derive classes - haskell

So, I found myself doing something like this:
newtype T x = T x deriving (Eq, Ord, ...)
And I thought this was annoying, so I'm thinking about making a package, using Template Haskell, that adds all the instances in base.
Perhaps it could even be more flexible than just dealing with what's above.
Firstly, it seems like Template Haskell can only spit out declarations, so I think I want to use standalone deriving. In general, I think I want to produce declarations something like this:
deriving instance (F x1, F x2, ... , F xn) => T x1 x2 x3
Where F is replaced by Eq, Ord, etc.
But the right hand side could be a bit more complex, for example:
deriving instance (F x1, F x2, ... , F xn) => T x1 (Maybe x2) x3
Or maybe even
deriving instance (F x1, F x2, ... , F xn) => T x1 (T2 x2 x3)
You could even have repeats:
deriving instance F x => T x x
Lets simplify things for a moment here, and assume there is only one parameter on the left. So we're looking at instances like this:
deriving instance F x => T (some stuff involving x)
I figure what I need is a function like the following:
(Name -> Type) -> Q [Dec]
Then I keep each class in base in a list (i.e. Eq, Ord etc). Then for each class of that list, I create a dummy variable, apply the class to it on the left hand side of the =>, and pass it to the Name -> Type argument passed to get the right hand side of the =>. I can the spit that out as a splice.
I think I can do the Template Haskell for the above function, but the problem is, how does a user use that Template Haskell function?
I think something like \x -> [| UserT x x |] won't work, will it?
I want the user to be able to do something like:
data A t = A t (Maybe t)
deriveClasses (\x -> A x)
How can I make this sort of thing nice for the end user? I hope this question makes some sort of sense, the thing I'm currently most focused on is a form that's easy for the user to use. When it comes to the actual writing of the Template Haskell I think I should be able to handle that.

Related

Haskell nested lists with newtype

Disclaimer: I am new to working with haskell.
I am working with proving logical formulas in haskell. I have trouble understanding how to work with newtypes and datas properly.
I have defined the following types to represent logical formulas that have the structure: (a or b or c) and (d or e) and (f) etc.
data Literal x = Literal x | Negation x
deriving (Show, Eq)
newtype Or x = Or [Literal x]
deriving (Show, Eq)
newtype And x = And [Or x]
deriving (Show, Eq)
I want to write a function that can filter on the literals (i.e. take out certain a b or c based on some condition). Naively I thought this should be similar to filtering on [[Literal x]] but I cannot seem to get it to work.
My current method is something like:
filterLit :: Eq x => And x -> And x
filterLit = map (\(Or x) -> (filter (\(Lit l) -> condition l) x))
This doesn't type. I feel like I'm missing some syntax rules here. Let me know if you have suggestions on how I should approach it.
\(Or x) -> filter (\(Lit l) -> condition l) x
Let's check the type of this function.
The domain must have type Or x. That's OK.
The codomain is the result of filter, hence it is a list. Let's only write [....] for that.
Hence, the function is Or x -> [....].
If we map that, we get [Or x] -> [[....]]. This is not the same as the claimed type And x -> And x -- a type error is raised.
First, you want your lambda to have type Or x -> Or x. For that, you can use \(Or x) -> Or (filter .....).
Then, you want filterLit to be something like
filterLit (And ys) = And (map ....)
so that it has the right type.

overriding default Eq definition for specific pattern

Suppose I have defined some data type that derives Eq but want to insert my own definition of (==) for some pattern. Is there any way to do this or do I have to define (==) for every pattern?
e.g.
data Asdf = One Char | Two Char Char --(deriving Eq)
instance Eq Asdf where
(==) (One _) (One _) = True
--otherwise use what the derived definition would have done
--can I do this without defining these patterns myself?
To do what you're trying to do, you have to define it yourself, and that means you have to define it for every pattern.
Basically data MyType x = A x | B x x deriving (Eq) will add a default derivation equivalent to,
instance Eq x => Eq (MyType x) where
A x1 == A x2 = x1 == x2
B x1 x2 == B x3 x4 = x1 == x3 && x2 == x4
_ == _ = False
Note that it figures out the necessary dependencies (the Eq x => part above) as well as fills in the diagonal cases -- the special cases among the n2 possible matches where the same constructor was used.
As far as I know, it does this definition all-at-once and there is no way to dig into an existing instance declaration to mess with it -- and there is a good reason for this; if they let you do this then that would mean that as codebases grow, you could not look at an instance derivation or a deriving (Eq) clause and be confident that you know exactly what it means, since some other part of the code might monkey-patch that Eq instance to do something nefarious.
So one way is to redefine the diagonal yourself. But that's not the only way. There is at least one alternative which may work if it's easier to modify several usage sites than to shove all n constructors into a single thing:
newtype EverythingIsEqual x = E x deriving (Show)
instance Eq (EverythingIsEqual x) where
_ == _ = True
data MyType x = A (EverythingIsEqual x) | B x x deriving (Show, Eq, Ord)
This newtype allows you to strategically modify certain terms to have a different Eq relation at no runtime cost -- in fact this is pretty much one of the two central arguments for newtypes; aside from the lesser one where "I want to have a type-level difference between these two Strings but they ARE just strings and I don't want to pay any performance penalty," there is the greater argument of "sometimes we want to tell Haskell to use a different Ord dictionary without messing with any of the values that this dictionary acts upon, we just want to swap out the functions."
This question discusses how to do something very similar for the Show instance, using the https://hackage.haskell.org/package/generic-deriving package: Accessing the "default show" in Haskell?
See this answer in particular: https://stackoverflow.com/a/35385768/936310
I recently used it for the Show instance recently, and it worked wonderfully. You can similarly derive Eq as well for your type, assuming it's regular enough.

Haskell: when to use type class and when to use concrete type?

When declaring functions, we could either use type class or concrete type(Am I right?) So I can use "Num" as type indicator or "Int". I'm not sure if "Int" has any definition out of "Num"? Can I define my own concrete type that "inherit" from "Num"?
I ask this question from java/C# inheritance perspective, just begin with Haskell. Would you give some hints?
From the OO perspective, a type class is something like an interface or a trait. In Haskell you generally use concrete types when you require a certain structure of the datatype (because you will unpack it), and a type class when you just want a certain behavior. For example, you can write
f :: Int -> Int -> Int
f x y = x + y
but you do not use the internal structure of Ints here; you just need something that supports addition, which is Num (note that it has a (+) in method list):
f :: Num a => a -> a -> a
f x y = x + y
And yes, of course, you can declare that your own class supports the Num interface. Look at the link above, there is a list of methods called "minimal complete definition". This is what other functions that use it will rely on. In a pinch, you may explicitly set some methods to undefined, but you'll get a runtime error if someone tries to call them:
data MyData = MyData Int Int
instance Num MyData where
(MyData x1 y1) + (MyData x2 y2) = MyData (x1 + y1) (x2 + y2)
(*) = undefined
...
See how you use your knowledge of MyData structure to abstract possible users of your class from it? If they want to add two values of this type together, they do not need to know how the data is arranged inside, they just need to know that it is an instance of Num.

Applicative without a functor

I have a type Image which is basically an c-array of floats. It is easy to create functions
such as map :: (Float -> Float) -> Image -> Image, or zipWith :: (Float -> Float -> Float) -> Image -> Image -> Image.
However, I have a feeling that it would also be possible to provide something that looks like an applicative instance on top of these functions, allowing more flexible pixel level manipulations like ((+) <$> image1 <*> image2) or ((\x y z -> (x+y)/z) <$> i1 <*> i2 <*> i3). However, the naive approach fails, since Image type cannot contain things other than floats, making it impossible to implement fmap as such.
How could this be implemented?
Reading the comments, I'm a little worried that size is under the carpet here. Is there a sensible behaviour when sizes mismatch?
Meanwhile, there may be something you can sensibly do along the following lines. Even if your arrays aren't easy to make polymorphic, you can make an Applicative instance like this.
data ArrayLike x = MkAL {sizeOf :: Int, eltOf :: Int -> x}
instance Applicative ArrayLike where
pure x = MkAL maxBound (pure x)
MkAL i f <*> MkAL j g = MkAL (min i j) (f <*> g)
(Enthusiasts will note that I've taken the product of the (Int ->) applicative with that induced by the (maxBound, min) monoid.)
Could you make a clean correspondence
imAL :: Image -> ArrayLike Float
alIm :: ArrayLike Float -> Image
by projection and tabulation? If so, you can write code like this.
alIm $ (f <$> imAL a1 <*> ... <*> imAL an)
Moreover, if you then want to wrap that pattern up as an overloaded operator,
imapp :: (Float -> ... -> Float) -> (Image -> ... -> Image)
it's a standard exercise in typeclass programming! (Ask if you need more of a hint.)
The crucial point, though, is that the wrapping strategy means you don't need to monkey with your array structures in order to put functional superstructure on top.
How would you expect to perform operations on pixels in an image? That is, for ((+) <$> image1 <*> image2), would you want to perform all the operations in Haskell and construct a new resulting image, or would you have to call C functions to do all the processing?
If it's the former, pigworker's answer is the approach I would take.
If instead it's required that all image manipulations be handled via C, how about creating a small DSL to represent the operations?
You'll get a much more compositional Image type if you generalize the "pixel" type from Float and extend from finite & discrete domain (arrays) to infinite & continuous domain.
As a demonstration of these generalizations, see the paper Functional Images and a corresponding gallery of (finite samplings of) example images.
As a result, you get instances of Monoid, Functor, Applicative, Monad, and Comonad.
Moreover, the meanings of these instances are entirely determined by the corresponding instances for functions, satisfying the principle of semantic type class morphisms, as described in the paper Denotational design with type class morphisms.
Section 13.2 of that paper briefly describes imagery.

Haskell default superclass instances

I want to take some of the boilerplate out of Num declarations for a few custom classes (call them Monomial and Polynomial). Instead of writing
instance Num (Monomial) where
f - g = f + (negate g)
abs _ = undefined
Is there a way to get around this? I came across default superclass instances and something called "the strathclyde haskell enhancement" which if implemented might let me write something like,
class SimpleNum a => Num a where
(+) :: a -> a -> a -- standard ring stuff
(*) :: a -> a -> a
one :: a
zero :: a
instance Num (SimpleNum a) where
f - g = f + (negate g)
abs _ = undefined
What's the usual / simple way of dealing with this?
The usual ways of dealing this is to do at least one or more of the following:
Grumble a lot.
Write helper functions like this:
simpleMinus f g = f + (negate g)
Use tools like Template Haskell and Derive.
Attempt to implement extensions like the one you mention. (This unfortunately not as easy as you might think.)

Resources