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.
Related
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
In imperative/object oriented programming with mutable state, it would be very common and useful to declare a structure such as the following:
struct RigidBody {
float m_mass;
float m_inverseMass;
Mat3 m_localInverseInertiaTensor;
Mat3 m_globalInverseInertiaTensor;
Vec3 m_globalCentroid;
Vec3 m_localCentroid;
Vec3 m_position;
Mat3 m_orientation;
Vec3 m_linearVelocity;
Vec3 m_angularVelocity;
};
Source: http://allenchou.net/2013/12/game-physics-motion-dynamics-implementations/
There are many properties here that are able to be computed directly from others, such as m_inverseMass from m_mass. In a stateless programming language like Haskell, getting derived values is easy enough:
data RigidBody = RigidBody {mass :: Float}
inverseMass :: RigidBody -> Float
inverseMass body = 1 / mass body
But this computes the inverseMass every time we need it, which can get expensive especially in domains where performance is critical, like physics simulation. I've considered memoization, but I wasn't sure if this is a good way of expressing this lazy evaluation of dependent properties, as it seemed to be a complicated solution. How would I store derivative values without having to recompute them?
As #4castle and #Shersh note, a simple approach would be to include the derived value in the data type:
data RigidBody = RigidBody
{ m_mass :: Float
, m_inverseMass :: Float }
and then use a smart constructor to make new RigidBodys:
rigidBody mass = RigidBody mass (1/mass)
The expression 1/mass will create a thunk for m_inverseMass which, after it is first evaluated, will be available without recalculation, so it provides a sort of auto memoization.
More general transformations, like changing the position and properly updating all the global* fields based on the local* values would be handled in a similar manner. As a simplified example:
module Rigid where
type Vec3 = Double -- just to type check
data RigidBody = RigidBody
{ m_mass :: Float
, m_inverseMass :: Float
, m_pos :: Vec3
, m_localCentroid :: Vec3
, m_globalCentroid :: Vec3
}
rigidBody mass pos centroid =
RigidBody mass (1/mass) pos centroid (centroid + pos)
move body delta =
rigidBody (m_mass body)
(m_pos body + delta)
(m_localCentroid body)
In an application that's performance critical, you would want to take steps to introduce strictness in appropriate places so you don't build up huge piles of unevaluated thunks.
You can store inverseMass as Maybe Float inside RigidBody. When inverseMass is Just someMass you just extract this value. If it's Nothing you compute it and store inside RigidBody. The problem is with this store part. Because as you may know objects are immutable in Haskell.
Naive but simple solution would be to return RigidBody after every computation like this:
data RigidBody = RigidBody
{ rigidBodyMass :: Float
, rigidBodyInverseMass :: Maybe Float }
inverseMass :: RigidBody -> (Float, RigidBody)
inverseMass b#(RigidBody _ (Just inv)) = (inv, b)
inverseMass (RigidBody mass Nothing) = let inv = 1 / mass
in (inv, RigidBody mass (Just inv))
If you have a lot of such fields you may find such approach extremely tedious. And it's not very convenient to write code using such functions. So here is the place where State monad becomes handy. State monad can just keep current RigidBody inside explicit state and update it accordingly through all you stateful computation. Like this:
inverseMass :: State RigidBody Float
inverseMass = do
RigitBody inv maybeInverse <- get
case maybeInverse of
Just inv -> pure inv
Nothing -> do
let inv = 1 / mass
put $ RigidBody mass (Just inv)
pure inv
Later you can just use inverseMass multiple times and only during your first call inverse of mass will be calculated.
You see, in imperative programming languages like C++ state is explicit. You want to update fields of RigidBody. So basically you have some object of type RigidBody which stores some states. Because state is implicit you don't need to specify in your functions that they change fields of RigidBody. In Haskell (and every good programming language) you specify explicitly what is your state and how you will change it. You specify explicitly what objects you want to work with. inverseMass monadic action (or just function if you want) will update your explicit state depending on the current state at the moment of calling this function. This is more or less idiomatic approach in Haskell for such sort of tasks.
Well, another idiomatic solution: just create values of your data type with all fields set to some function calls. Because Haskell is lazy such fields are calculated first time only when they are needed.
Let's say I create a Person type:
type Age = Int
type Height = Int
data Person = Person Age Height
This is all well, but I'd like to make sure that Age and Height cannot be added, because that makes no sense. I'd like a compile error when trying to do so.
In it's current form, this does not cause a compile error:
stupid (Person age height) = age + height
So I think about using newtype or even data for Age and Height:
newtype Age = Age Int
newtype Height = Height Int
data Person = Person Age Height
but still:
stupid (Person (Age age) (Height height)) = age + height
Is there a way of preventing age and height from being added? Or is what I'm asking for unreasonable?
By unwrapping the newtypes using the constructors Person and Height, you essentially instruct the compiler to forget the type distinction. That of course makes it legal to write age + height, but that's not to blame on the newtypes, like it's not to blame on the train driver if you smash the window, jump out and get injured!†
The way to prevent such incorrect operation is to not unwrap the newtypes. The following will cause an error, if Age and Height are newtypes:
stupid (Person age height) = age + height
...not just because age and height are different types, also because neither actually supports an addition operation (they aren't Num instances). Now that's fine, as long as you don't really need to perform any operations on these values.
Chances are however that at some point you will need to perform some operation on those values. This should not require the user to unwrap the actual newtype constructors.
For such physical quantities like age and height, there are a few options to do it type-safely:
Add VectorSpace instances. That will allow you to add one height to another, and scale heights by fractions, but not add a height to something entirely different.
import Data.AdditiveGroup
import Data.VectorSpace
instance Additive Height where
Height h₀ ^+^ Height h₁ = Height $ h₀+h₁
zeroV = Height 0
instance VectorSpace Height where
type Scalar Height = Double
μ *^ Height h = Height . round $ μ * fromIntegral h
This simple instance is mighty handy for some science use cases, though probably not that useful for your application.
Add meaningful unit-specific accessors. In modern Haskell, those would be lenses:
import Control.Lens
heightInCentimetres :: Lens' Height Int
heightInCentimetres = lens (\(Height h)->h) (\(Height _) h->Height h)
ageInYears :: Lens' Age Int
ageInYears = lens (\(Age a)->a) (\(Age _) a->Age a)
This way, if someone needs to work with an actual number of years of someone's age or modify it, they can do so, but they need to be explicit that these are years they're talking about. Of course, accessing the years and height as an integer number again makes it possible to circumvent the type distinction and intermingle ages with height, but this can hardly happen by accident.
Go all the way to a library for physical quantities.
import Data.Metrology.SI
type Height = Length
type Age = Time
This allows you to perform all kinds of physically legit operations while preventing nonsensical ones.
†Jumping out of a train is actually more dangerous. Rather like unsafeCoerce, which really instructs the compiler to throw all type-safety out of the window and can easily cause crashes or demons flying out of your nose.
This is actually a common pattern. Put the data type you want to protect into a module of its own:
module Quantities (
Age, Height, -- NOTE: constructors not exported
prettyHeight -- ...
) where
newtype Age = Age Int
newtype Height = Height Int
-- any operations that need to see the int, e.g.:
prettyHeight :: Height -> String
prettyHeight (Height h) = show h ++ "cm"
If you do not add an explicit export list to the module, everything will be exported, including the constructors Age and Height. In the above code, they are not exported, thus you can only access the Int values from within this module. All operations which actually have to work with the wrapped Int have to be in this module.
Now, import this module wherever you need it:
module Person where
import Quantities
data Person = Person Age Height
test (Height h) = () -- This will not compile, Height not in scope.
Any other module except Quantities can no longer deconstruct Height or Age.
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
To declare constant variables I can do following in Ruby
class COLOR
RED = 10
BLUE = 20
GREEM = 30
end
COLOR::RED returns 10, COLOR::BLUE returns 20, and so on. How do I accomplish that in Haskell?
I want to have a namespace name in front of my variable name. Maybe the example above is not a good example. For the case below, you can see including a namespace name will make a variable much easier to understand.
class BASEBALL_TEAM
GIANTS = 15
METS = 30
REDS = 45
...
end
BASEBALL_TEAM::GIANTS is much clear than GIANTS.
based on the comments below, it seems the only way I can accomplish it is by doing something like below:
module Color (Color) where
data Color = Red | Blue | Green deriving (Eq, Show, Ord, Bounded, Enum)
fromEnum' x = (fromEnum x) + 10
to get integer value of 10 for Color.Red, I have to write fromEnum Color.Red, the syntax is not very clean.
Untagged constants are bad. If you go with bunch of Int constants then you lose type-checking (think about possible values that Int -> whatever function takes as opposed to SomeConstType -> whatever) and possibly introduce bugs. You want a strong type instead:
data Colour = Red | Blue | Green deriving (Show, Eq, Enum)
Also, representing those values as integers is not really necessary in most cases. If you actually do need it, Enum typeclass provides toEnum and fromEnum.
As for namespaces: modules are namespaces in Haskell. Put your type in a module and then you can import it qualified and you'll have your prefix:
-- Colours.hs
module Colours (Colour) where
data Colour = ...
-- SomeOtherModule.hs
module SomeOtherModule where
import qualified Colours
foo = Colours.Red
That said, creating modules just for this one type with constants (or importing them qualified) is not really necessary, because you can easily trace things by their types.
Things are constant in Haskell by default, so
red = 10
blue = 20
green = 30
would be equivalent.
A more interesting question would be why you want to do this? There are likely better ways to accomplish what you want in Haskell. The answer by #CatPlusPlus shows a good way of doing this.
This seems like a very basic Haskell question, so I'll politely point you to Learn you a Haskell, which, in my opinion, is the best resource to get started with Haskell.
Another promising resource for learning Haskell is FP complete's School of Haskell, which is currently in beta, but I haven't tried it myself. This is a more interactive setting, where you can directly try things out in the browser.