type parameters in Haskell - haskell

I want to create a type Pixel, and make it an instance of the Eq and Show class. However, i've been reading information from a lot of places, and got really confused with this.
Here's some info on the type i need to create:
I have to store two numbers (the position of the pixel and a value from 0 to 255).
Two pixels are equal if they have the same value, whatever their position is.
For the Show instance, i need to print the position and the value.
Here's my attempt at this:
type position = Float
type greyScale = Int
type Pixel = (position, greyScale)
instance Eq Pixel where
greyScale == greyScale = True
instance Show Pixel where
show position = position
show greyScale = greyScale
is this a correct way to do it ?

Type names have to start with a capital letter. So, your definitions actually should look like this, since you are only defining type synonyms:
type Position = Float
type GreyScale = Int
For Pixel: It looks like you wanted to define a data type, not just a synonym, so you should do something like this:
data Pixel = Pixel Position GreyScale
Next: The Eq instance compares two Pixels, so you have to represent them as such:
instance Eq Pixel where
Pixel pos1 greyScale1 == Pixel pos2 greyScale2 = greyScale1 == greyScale2
greyScale1 == greyScale2 just compares the two greyScales, which is what you want.
Also, I would not recommend overwriting Show instances to assure that read . show == id holds. (You can automatically derive specific instances by adding deriving (Instance1, Instance2, ..) after the datatype declaration). Rather than meddling with it I would define separate functions:
showPosition :: Pixel -> String
showPosition (Pixel position greyScale) = show position
and
showGreyscale :: Pixel -> String
showGreyscale (Pixel position greyScale) = show greyScale

Related

Representing a chessboard in Haskell

I'm trying to implement a function in Haskell that returns a list containing all possible moves for the player who's up. The function's only argument is a String composed of an actual state of the board (in Forsyth-Edwards Notation ) followed by the moving player(b/w).
Notation example : rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w (starting board state)
A move is transmitted as a string of the form [origin]-[destination]. The destination is always a position of the form [column][row], where the lower left square is called a1 and the upper right square is called h8. A move would be for example the move "b3-c4". (no castling/En-passant).
In Java I would use a 2d Array for the Board, but in Haskell I can't find a similar solution (I'm new to functional programming).
What would be a good way/data structure to represent the chess board in?
There are two primary options for storing a board state. The first is a 2D list of Maybe, where a piece would be represented as, e.g. Just $ Piece Black King and a blank square would be represented as Nothing. This optimizes determining if a square is occupied over listing where pieces are (which might be important if you plan to add rendering later):
type Board = Vector (Vector (Maybe Piece))
data Piece = Piece { color :: Color
, type :: PieceType }
The second option is to store a list of pieces and their locations. This implementation is faster to enumerate the locations of all pieces, but slower to check if there is a piece on a particular square:
type Pieces = [Placement]
type Placement = { position :: Position
, piece :: Piece }
data Position =
Pos { rank :: Int
, file :: Int }
deriving (Show, Eq)
data Piece =
Piece { color :: Color
, ptype :: PieceType }
deriving Show
EDIT: It's worth noting that with an 8x8 grid and a maximum of 32 pieces on the board, the performance hit either way is going to be minimal unless you're doing a lot of calculations.
Data.Vector, has constant time lookup by index.
A chessboard can be represented as a Vector (Vector (Maybe Piece)). To define Piece, see ADTs

Get the Height and Width of an image

I'm very new to Haskell so I apologise if this is too basic, or if it makes very little sense. I'm trying to read an image; I can get it to a list of pixel data with the following code:
data Pixel = Pixel {
red :: Integer,
green :: Integer,
blue :: Integer,
alpha :: Integer
} deriving (Show)
getImagePixelArray :: FilePath -> IO (Codec.Picture.Repa.Img RGBA)
getImagePixelArray fp = do
img <- (either error return =<< readImageRGBA fp)
return img
getImagePixelData :: Codec.Picture.Repa.Img RGBA -> [(Word8,Word8,Word8,Word8)]
getImagePixelData img = R.toList (collapseColorChannel img)
rawPixelToPixel :: (Word8,Word8,Word8,Word8) -> Pixel
rawPixelToPixel (r, g, b, a) = Pixel {
red = (toInteger r),
green = (toInteger g),
blue = (toInteger b),
alpha = (toInteger a)
}
main = do
imageData <- getImagePixelArray "./images/image1.png"
let imageRawPixels = getImagePixelData imageData
let asPixels = Prelude.map rawPixelToPixel imageRawPixels
mapM print asPixels
I more or less follow what's going on, but my knowledge of Haskell is still limited, so when it comes to making sense of api documentation, I'm struggling a little.
I really want to be able to parse the positions of the pixels; I understand how to do that if I know the width and height of an image, but I can't figure out how to get the width/height of an image.
I'm making my way through a Haskell course, but I'm also trying to put it to some practical use along the way to help the concepts sink in.
Start with the documentation. None of what you're asking for is obviously available on Img, so where else could it be? There's a related Image type, mentioned in convertImage's documentation - I wonder what that is. As it turns out, it has a width and a height. How can we get an Image from our Img, then? imgToImage will give us a DynamicImage, which has several constructors each containing an Image. Figure out what kind of Image you have inside your DynamicImage, and then ask that Image its dimensions.
Perhaps there is something easier with the other lens-y stuff in that module, but it is not obvious to me, and this approach seems simple enough, if a hassle.

Generate 2D list with given dimensions in Haskell

I am trying to generate a list of lists with a specified dimension.
the data type of this list looks something like this:
data A = X | Y | Z
so the list is of type [[A]]. (A is an instance of the Show type class so don't worry about that).
The user gives in a certain dimension (lets say width = 3 and height = 4), so the content could look like this:
[[X,Y,Z],
[Y,Y,X],
[Y,X,Z],
[X,Z,Z]]
How can I generate a width X height 'matrix', the values aren't all that important at the moment.
thanks in advance.
EDIT: (for clarity reasons)
I just want to know how to generate a 'matrix' of type [[A]] with the width and height as user input.
So width = number of elements in the inner list, height = number of lists in the outer list.
To generate a 3x4 nested list filled by a certain element, you can use:
data A = X | Y | Z deriving (Show)
generate width height = replicate height . replicate width
main = print $ generate 3 4 X
to get [[X,X,X],[X,X,X],[X,X,X],[X,X,X]].
Note that nested lists are not a great substitute for a 2D array in C/Java if the goal is to do frequent point updates. In those cases, use Data.Map or Data.Array.

haskell - LYAH - Making our own Types and our Type Classes

The haskell code below compiles, Ok.
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
Is it possible to write something in line with the code below (Code fails compiling):
data LengthQty = Radius Float | Length Float | Width Float
data Shape = Circle Point Radius
Idea behind this attempt is that Radius, Length and Width are representing Physical Quantity Length.
Please note that in the second part second line if written like
data Shape = Circle Point LengthQty
Then, it compiles, but in that case the "LengthQty" can be anything like Length, Width or Radius, where only Radius is required.
(1) What is wrong in second part?
(2) How it can be corrected to implement the idea of Physical Quantity Length (LengthQty)?
The reason that your code doesn't compile is that the right-hand side of a data declaration must be a constructor followed by a list of types, i.e. of the form
data {-type-} = {-constructor-} {-type-} ... {-type-}
In your example, when you define
data LengthQty = Radius Float | Length Float | Width Float
you have made LengthQty a type whereas Radius, Length and Width are constructors. Therefore when you write
data Shape = Circle Point Radius
the compiler sees something of the form
data {-type-} = {-constructor-} {-type-} {-constructor-}
i.e. it sees a constructor where it is expecting a type, so it throws an error. In the original code, the symbol Radius was used for both a constructor and a type. When the compiler sees
data Shape = Circle Point Radius
it knows that Radius in this context has to be a type, so there is no possibility of confusion with the constructor radius.
With this in mind, you can make your code compile correctly if you just write
data Shape = Circle Point LengthQty
and you can get a particular instance of a circle with
circle :: Shape
circle = Circle (Point 0 0) (Radius 1)
This compiles:
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
data LengthQty = R Float | Length Float | Width Float
Radius is name of the type and also of data constructor of type Float -> Radius; R is a data constructor of type Float -> LengthQty. You can't have two different data constructors with same name. The name Radius is already taken.
The following also works:
data LengthQty = R Radius | Length Float | Width Float
Without R, Radius by itself would be a data constructor of type :: LengthQty, which would, again, clash with Radius :: Float -> Radius.
The useful difference between
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
and
data LengthQty = Radius Float | Length Float | Width Float
is the way Haskell's type system handles them. Haskell has a powerful type system, which makes sure that a function is passed data that it can handle. The reason you'd write a definition like LengthQuantity is if you had a function which could take either a Radius, Length, or Width, which your function can't do.
If you did have a function which could take a Radius, Length, or Width, I'd write your types like this:
data Point = Point Float Float
data Radius = Radius Float
data Shape = Circle Point Radius
data LengthQty = R Radius
| L Length
| W Width
This way, functions that can only take a Radius benefit from that more specific type checking.

Haskell Algebraic Data Types

I have the following for an HTML font tag:
data Color = HexColor Int | RGBColor Int Int Int | ColorString String deriving Show
data FontAttribute = Size Int | Face String | FontColor Color deriving Show
data Font = Font [FontAttribute] deriving Show
I construct one like so:
Font [Size 23,Face "Arial",Color (RGBColor 240 23 43)]
My concern is that the FontColor data/value constructor which has type FontAttribute requires a Color type as an argument. This means that Color is a generic type attribute for any kind of tag, and a specific tag has a specific subset of attributes (in this case Font has FontAttribute, which can be Size, Face or FontColor). Is there a clearer way to express this, or is my implementation sound?
Color is just a type, not an attribute. There is nothing in the type system to indicate that Color has any special relationship with FontAttribute. All that happens when you define the FontAttribute data type is that it creates a constructor called FontColor which is an ordinary function with the following type signature:
FontColor :: Color -> FontAttribute
So if you declared some new type called Link:
data LinkAttrubute = LinkColor Color | ...
Then Color could be stored in a LinkAttribute, too. A constructor does not imply an exclusive relationship with only that data type. All your FontAttribute data type says is that it MIGHT contain just a Color.
Haskell has no built-in concept of attributes because it has no built-in concept of objects. HOWEVER, you can model attributes using the Lens type from the data-lens (or fclabels) package. I would link you the packages, but I'm on my phone and it is difficult.

Resources