Iterating over custom data types in Haskell - haskell

I have a custom data type that looks like this:
data Circle = Circle
{ radius :: Float
, xPosition :: Float
, yPosition :: Float
}
I want to be able to write a scale function that can take a given circle and change its size like this:
aCircle = Circle 1.5 1 1
scaleFn aCircle 10
The desired output for this example with scale of 10 would be:
Circle 15 10 10
How can I create a function where I can iterate over each field and multiple the values by a constant? In my actual use case I need a way to map over all the fields as there are many of them.

Scaling by a factor is generally a vector space operation. You could do the following:
{-# LANGUAGE TypeFamilies, DeriveGeneric #-}
import Data.VectorSpace
import GHC.Generics (Generic)
data Circle = Circle
{ radius :: Float
, xPosition :: Float
, yPosition :: Float
} deriving (Generic, Show)
instance AdditiveGroup Circle
instance VectorSpace Circle where
type Scalar Circle = Float
main = print $ Circle 1.5 1 1 ^* 10
(result: Circle {radius = 15.0, xPosition = 10.0, yPosition = 10.0}).
(requires vector-space >= 0.11, which has just added support for generic-derived instances.)
However I should remark that Circle as such is not really a good VectorSpace instance: adding two circles doesn't make any sense, and scaling by a negative factor gives a bogus radius. Only define such an instance if your real use case follows the actual vector space axioms.
What you really want for a type like Circle is something like diagrams' Transformable class. But I don't think there's any automatic way to derive an instance for that. In fact, since diagrams has – unfortunately IMO – switched from vector-space to linear, something like this has become considerably tougher to do even in principle.

You can use "scrap your boilerplate":
import Data.Generics
data Circle = Circle
{ radius :: Float
, xPosition :: Float
, yPosition :: Float
}
deriving (Show, Data)
circleModify :: (Float -> Float) -> Circle -> Circle
circleModify f = gmapT (mkT f)
Intuitively, above, mkT f transforms f into a function which is applicable to any type: if the argument of mkT f is a Float, then f is applied, otherwise the argument is returned as it is.
The newly constructed general function is called a "transformation": the T in mkT stands for that.
Then, gmapT applies the transformation mkT f to all the fields of the circle. Note that is a field contained, say, (Float, Bool) that float would be unaffected. Use everywhere instead of gmapT to recursively go deeper.
Note that I'm not a big fan of this approach. If for any reason you change the type of a field, that change will not trigger a type error but gmapT (mkT ...) will now simply skip over that field.
Generic programming can be convenient, but sometimes a bit too much, in that type errors can be silently transformed into unexpected results at runtime. Use with care.

Related

Is it bad form to make new types/datas for clarity? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
I would like to know if it is bad form to do something like this:
data Alignment = LeftAl | CenterAl | RightAl
type Delimiter = Char
type Width = Int
setW :: Width -> Alignment -> Delimiter -> String -> String
Rather than something like this:
setW :: Int -> Char -> Char -> String -> String
I do know that remaking those types effectively does nothing but take up a few lines in exchange for clearer code. However, if I use the type Delimiter for multiple functions, this would be much clearer to someone importing this module, or reading the code later.
I am relatively new to Haskell so I do not know what is good practice for this type of stuff. If this is not a good idea, or there is something that would improve clarity that is preferred, what would that be?
You're using type aliases, they only slightly help with code readability. However, it's better to use newtype instead of type for better type-safety. Like this:
data Alignment = LeftAl | CenterAl | RightAl
newtype Delimiter = Delimiter { unDelimiter :: Char }
newtype Width = Width { unWidth :: Int }
setW :: Width -> Alignment -> Delimiter -> String -> String
You will deal with extra wrapping and unwrapping of newtype. But the code will be more robust against further refactorings. This style guide suggests to use type only for specializing polymorphic types.
I wouldn't consider that bad form, but clearly, I don't speak for the Haskell community at large. The language feature exists, as far as I can tell, for that particular purpose: to make the code easier to read.
One can find examples of the use of type aliases in various 'core' libraries. For example, the Read class defines this method:
readList :: ReadS [a]
The ReadS type is just a type alias
type ReadS a = String -> [(a, String)]
Another example is the Forest type in Data.Tree:
type Forest a = [Tree a]
As Shersh points out, you can also wrap new types in newtype declarations. That's often useful if you need to somehow constrain the original type in some way (e.g. with smart constructors) or if you want to add functionality to a type without creating orphan instances (a typical example is to define QuickCheck Arbitrary instances to types that don't otherwise come with such an instance).
Using newtype—which creates a new type with the same representation as the underlying type but not substitutable with it— is considered good form. It's a cheap way to avoid primitive obsession, and it's especially useful for Haskell because in Haskell the names of function arguments are not visible in the signature.
Newtypes can also be a place on which to hang useful typeclass instances.
Given that newtypes are ubiquitous in Haskell, over time the language has gained some tools and idioms to manipulate them:
Coercible A "magical" typeclass that simplifies conversions between newtypes and their underlying types, when the newtype constructor is in scope. Often useful to avoid boilerplate in function implementations.
ghci> coerce (Sum (5::Int)) :: Int
ghci> coerce [Sum (5::Int)] :: [Int]
ghci> coerce ((+) :: Int -> Int -> Int) :: Identity Int -> Identity Int -> Identity Int
ala. An idiom (implemented in various packages) that simplifies the selection of a newtype that we might want to use with functions like foldMap.
ala Sum foldMap [1,2,3,4 :: Int] :: Int
GeneralizedNewtypeDeriving. An extension for auto-deriving instances for your newtype based on instances available in the underlying type.
DerivingVia A more general extension, for auto-deriving instances for your newtype based on instances available in some other newtype with the same underlying type.
One important thing to note is that Alignment versus Char is not just a matter of clarity, but one of correctness. Your Alignment type expresses the fact that there are only three valid alignments, as opposed to however many inhabitants Char has. By using it, you avoid trouble with invalid values and operations, and also enable GHC to informatively tell you about incomplete pattern matches if warnings are turned on.
As for the synonyms, opinions vary. Personally, I feel type synonyms for small types like Int can increase cognitive load, by making you track different names for what is rigorously the same thing. That said, leftaroundabout makes a great point in that this kind of synonym can be useful in the early stages of prototyping a solution, when you don't necessarily want to worry about the details of the concrete representation you are going to adopt for your domain objects.
(It is worth mentioning that the remarks here about type largely don't apply to newtype. The use cases are different, though: while type merely introduces a different name for the same thing, newtype introduces a different thing by fiat. That can be a surprisingly powerful move -- see danidiaz's answer for further discussion.)
Definitely is good, and here is another example, supose you have this data type with some op:
data Form = Square Int | Rectangle Int Int | EqTriangle Int
perimeter :: Form -> Int
perimeter (Square s) = s * 4
perimeter (Rectangle b h) = (b * h) * 2
perimeter (EqTriangle s) = s * 3
area :: Form -> Int
area (Square s) = s ^ 2
area (Rectangle b h) = (b * h)
area (EqTriangle s) = (s ^ 2) `div` 2
Now imagine you add the circle:
data Form = Square Int | Rectangle Int Int | EqTriangle Int | Cicle Int
add its operations:
perimeter (Cicle r ) = pi * 2 * r
area (Cicle r) = pi * r ^ 2
it is not very good right? Now I want to use Float... I have to change every Int for Float
data Form = Square Double | Rectangle Double Double | EqTriangle Double | Cicle Double
area :: Form -> Double
perimeter :: Form -> Double
but, what if, for clarity and even for reuse, I use type?
data Form = Square Side | Rectangle Side Side | EqTriangle Side | Cicle Radius
type Distance = Int
type Side = Distance
type Radius = Distance
type Area = Distance
perimeter :: Form -> Distance
perimeter (Square s) = s * 4
perimeter (Rectangle b h) = (b * h) * 2
perimeter (EqTriangle s) = s * 3
perimeter (Cicle r ) = pi * 2 * r
area :: Form -> Area
area (Square s) = s * s
area (Rectangle b h) = (b * h)
area (EqTriangle s) = (s * 2) / 2
area (Cicle r) = pi * r * r
That allows me to change the type only changing one line in the code, supose I want the Distance to be in Int, I will only change that
perimeter :: Form -> Distance
...
totalDistance :: [Form] -> Distance
totalDistance = foldr (\x rs -> perimeter x + rs) 0
I want the Distance to be in Float, so I just change:
type Distance = Float
If I want to change it to Int, I have to make some adjustments in the functions, but thats other issue.

Algebraic Types - Haskell

I am working around with algebraic types in Haskell, doing some exercises from a worksheet. I got the following exercises:
Define an algebraic type Point for representing (the coordinates of) points in twodimensional space.
My code for this exercise:
data Point = Point Float Float
deriving (Show)
Using Point, define a modified version PositionedShape of the Shape data type which
includes the centre point of a shape, in addition to its dimensions.
Shape data previously defined:
data Shape = Circle Float |
Rectangle Float Float
deriving (Show)
My code for this exercise:
data PositionedShape = PositionedShape Shape Point
deriving (Show)
Now my question comes in this one:
Define a function:
haskell move :: PositionedShape -> Float -> Float -> PositionedShape
which moves a shape by the given x and y distances
My implementation for this was the following:
move :: PositionedShape -> Float -> Float -> PositionedShape
move (Shape (Point x y)) newX newY = Shape (Point newX newY)
This is returning me this error:
Week8.hs:103:7: error: Not in scope: data constructor ‘Shape’
Failed, modules loaded: none.
Can someone please explain me why this error and how can I solve it? I am getting a bit confused with algebraic types, I tried a lot of things but it just seems I can't get a solution.
You need to pattern match on data constructors (like Circle and Rectangle), not on type constructors as you're trying to do now (like Shape). For PositionedShape, they happen to have the same name, although you completely forgot the match on this one (and in fact, you don't need to care about the inner Shape at all except to copy it through). Also, move is meant to move the shape by the given distances, not to move it to a new given position;.
You need to use the PositionedShape constructor to break apart a PositionedShape You have used the Shape constructor instead.
Try starting with:
move (PositionedShape shape (Point old_x old_y)) [...]
How about
move (PointedShape s (Point x y)) dx dy = PointedShape s (Point (x+dx) (y+dy))

In Haskell how can I override the (==) and (/=) operators for a type class?

Say I have something like this
class Circle c where
x :: c -> Float
y :: c -> Float
radius :: c -> Float
data Location = Location { locationX :: Float
, locationY :: Float
} deriving (Show, Eq)
data Blob = Location { blobX :: Float
, blobY :: Float
, blobRadius :: Float,
, blobRating :: Int
} deriving (Show, Eq)
instance Circle Location where
x = locationX
y = locationY
radius = pure 0
instance Circle Blob where
x = blobX
y = blobY
radius = blobRadius
Say for example I want Circle types to be equal if their x and y points are equal. How can I compare instances of the type class with the (==) and (/=) operators. I know I can do something like this, but is it possible to overload the operators?
equal :: Circle a => Circle b => a -> b -> Bool
equal a b = (x a == x b && y a == y b)
I want to be able to compare with
(Location 5.0 5.0) == (Blob 5.0 5.0 ... ) should give me True
Zeroth, some standard imports:
import Data.Function (on)
import Control.Arrow ((&&&))
First, this is not a good idea. a==b should only be true if a and b are (for all purposes relevant to the user) interchangeable – that's clearly not the case for two circles which merely happen to share the same center point!
Second, it's probably not a good idea to make Circle a typeclass in the first place. A typeclass only makes sense when you want to abstract over something that can't directly be expressed with just a parameter. But if you just want to attach different “payloads” to points in space, a more sensible approach might be to define something like
data Located a = Located {x,y :: ℝ, payload :: a}
If, as seems to be the case, you actually want to allow different instances of Circle to coexist and be comparable at runtime, then a typeclass is entirely the wrong choice. That would be an OO class. Haskell doesn't have any built-in notion of those, but you could just use
data Blob = Blob
{ x,y :: ℝ
, radius :: ℝ
, rating :: Maybe Int }
and no other types.
https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/
Third, the instance that you asked for can, theoretically speaking, be defined as
instance (Circle a) => Eq a where
(==) = (==)`on`(x &&& y)
But this would be a truely horrible idea. It would be a catch-all instance: whenever you compare anything, the compiler would check “is it of the form a?” (literally anything is of that form) “oh great, then said instance tells me how to compare this.” Only later would it look at the Circle requirement.
The correct solution is to not define any such Eq instance at all. Your types already have Eq instances individually, that should generally be the right thing to use – no need to express it through the Circle class at all, just give any function which needs to do such comparisons the constraint (Circle a, Eq a) => ....
Of course, these instances would then not just compare the location but the entire data, which, as I said, is a good thing. If you actually want to compare only part of the structure, well, make that explicit! Use not == itself, but extract the relevant parts and compare those. A useful helper for this could be
location :: Circle a => a -> Location
location c = Location (x c) (y c)
...then you can, for any Circle type, simply write (==)`on`location instead of (==), to disregard any other information except the location. Or write out (==)`on`(x &&& y) directly, which can easily be tweaked to other situations.
Two circles that share a common center aren't necessarily equal, but they are concentric; that's what you should write a function to check.
concentric :: (Circle a, Circle b) => a -> b -> Bool
concentric c1 c2 = x c1 == x c2 && y c1 == y c2

How to make function useable only for a certain data constructor of an ADT?

I'm currently playing around with ADTs in Haskell and try to build an ADT Figure:
data Figure = Rect { x :: Integer, y :: Integer, width :: Integer, height :: Integer}
| Circle { x :: Integer, y :: Integer, radius :: Integer}
| CombiFigure Figure Figure
deriving (Eq, Show, Read)
Now I came across the question how to implement a function that should not accept every Figure, but e.g. only a Circle.
Do I already have a bad design? Or is there some best-practice how to do this?
As example, think about a diameter function. All that came to my mind (I'm a complete beginner in Haskell) are the following two options, using undefined or Maybe:
1:
diameter :: Figure -> Integer
diameter (Circle _ _ r) = 2 * r
diameter _ = undefined
2:
diameter :: Figure -> Maybe Integer
diameter (Circle _ _ r) = Just (2 * r)
diameter _ = Nothing
Are there more preferable ways on how to accomplish that?
Thanks!
You are correct that there is something not right here. The best way of thinking about it would be to start at the function diameter and decide what it's type should ideally be. You would likely come up with
diameter :: Circle -> Integer
diameter (Circle _ _ r) = 2 * r
because diameters are only defined for circles.
This means that you will have to augment your data structure by splitting out Circle (and Rect too):
data Figure = RectFigure Rect
| CircleFigure Circle
| CombiFigure Figure Figure
deriving (Eq, Show, Read)
data Rect = Rect { rectX :: Integer, rectY :: Integer, rectWidth :: Integer, height :: Integer}
deriving (Eq, Show, Read)
data Circle = Circle { circleX :: Integer, circleY :: Integer, circleRadius :: Integer}
deriving (Eq, Show, Read)
which is nice because it is now more flexible: you can write functions that don't care what Figure they are applied to, and you can write functions that are defined on specific Figures.
Now, if we are in a higher-up function and have a reference to a Figure and we want to compute its diameter if it's a CircleFigure, then you can use pattern matching to do this.
Note: using undefined or exceptions (in pure code) is likely a code smell. It could probably be solved by rethinking your types. If you have to indicate failure, then use Maybe/Either.
Your type definition by itself (i.e data Figure = ...) is introducing partial functions. e.g. even though width is of type width :: Figure -> Integer it can only work on Rect values:
\> width $ Rect 1 2 3 4
3
\> width $ Circle 1 2 3
*** Exception: No match in record selector width
so, you already have defined functions which can work on one figure but not another (similar to diameter function in the question).
That said, a 3rd solution would be to define Circle, Rectangle etc, as separate types; then, define a Figure type class which defines the common interface of these types.
class Figure a where
area, perimeter :: a -> Double
instance Figure Circle where
area = ...
perimeter = ...
Additionally each type may have their own exclusive functions. Or, you may add more interfaces, (i.e. type classes) which cover some but not all the figure types.
An advantage of type classes is that they are easier to extend; e.g. if one wants to add, say, a Triangle type later on, he can opt-in any type class which applies to a triangle, and define an instance only for those type classes.
Whereas in the data Figure = ... approach, you need to find every function which can take a Figure as argument and make sure it will handle a Triangle as well. If you are shipping a library then you do not have access to all these functions.
>> for the reference, there was a similar recent discussion of data declaration vs type classes on haskell cafe mailing list.

Ambiguous type variable 'blah' in the constraint... how to fix?

I'm trying to write a simple ray-tracer in Haskell. I wanted to define a typeclass representing the various kinds of surfaces available, with a function to determine where a ray intersects them:
{-# LANGUAGE RankNTypes #-}
data Vector = Vector Double Double Double
data Ray = Ray Vector Vector
class Surface s where
intersections :: s -> Ray -> [Vector]
-- Obviously there would be some concrete surface implementations here...
data Renderable = Renderable
{ surface :: (Surface s) => s
, otherStuff :: Int
}
getRenderableIntersections :: Renderable -> Ray -> [Vector]
getRenderableIntersections re ra = intersections (surface re) ra
However this gives me the error:
Ambiguous type variable 's' in the constraint:
'Surface'
arising from a use of 'surface'
(The actual code is more complex but I've tried to distill it to something simpler, while keeping the gist of what I'm trying to achieve).
How do I fix this? Or alternatively, given that I come from a standard OO background, what am I fundamentally doing wrong?
Please don't use existential types for this! You could, but there would be no point.
From a functional standpoint you can drop this typeclass notion of Surface entirely. A Surface is something that maps a Ray to a list of Vectors, no? So:
type Surface = Ray -> [Vector]
data Renderable = Renderable
{ surface :: Surface
, otherStuff :: Int
}
Now if you really want, you can have a ToSurface typeclass essentially as you gave:
class ToSurface a where
toSurface :: a -> Surface
But that's just for convenience and ad-hoc polymorphism. Nothing in your model requires it.
In general, there are a very few use cases for existentials, but at least 90% of the time you can substitute an existential with the functions it represents and obtain something cleaner and easier to reason about.
Also, even though it may be a tad too much for you to take in, and the issues don't exactly match, you might find useful some of Conal's writing on denotational design: http://conal.net/blog/posts/thoughts-on-semantics-for-3d-graphics/
In your getRenderableIntersections function you call surface. There is no way for the interpreter to figure out what instance of the class Surface you want to use. If you have two such instances:
instance Surface SurfaceA where
-- ...
instance Surface SurfaceB where
-- ...
How can the interpreter determine the type of surface?
The way you defined Renderable means there is a function surface :: Surface s => Renderable -> s.
Try creating an instance Surface SurfaceA and asking the following type query (given a simple constructor SurfaceA):
> :t surface (Renderable SurfaceA 0) -- What's the type of the expression?
So, what type is this expression? I bet you're expecting SurfaceA. Wrong. Take the type of surface. It takes a Renderable argument and we're passing it a Renderable argument. What is left after that? Surface s => s. That's the type of that expression. We still don't know what type does s represent.
If you want the type to be SurfaceA you need to change your code so it becomes something like surface :: Surface s => Renderable s -> s. This way what s is can be determined, because it is the same s used in Renderable.
EDIT: As suggested by #mokus, you could also try the ExistentialTypes extension. It allows "hiding" away type parameters on the right side of a type declaration.
data Renderable = forall s. Surface s => Renderable
{ surface :: s
, otherStuff :: Int
}
The HaskellWiki page I linked to above even has an example very similar to what you want to do.
EDIT: (By #stusmith) - For the record, I'm including code below which compiles based on these suggestions here. However I've accepted the answer which I think shows a better way of approaching things.
{-# LANGUAGE ExistentialQuantification #-}
data Vector = Vector Double Double Double
data Ray = Ray Vector Vector
class Surface_ s where
intersections :: s -> Ray -> [Vector]
data Surface = forall s. Surface_ s => Surface s
instance Surface_ Surface where
intersections (Surface s) ra = intersections s ra
data Renderable = Renderable
{ surface :: Surface
}
getRenderableIntersections :: Renderable -> Ray -> [Vector]
getRenderableIntersections re ra = intersections (surface re) ra

Resources