Reputation: 1047
I am trying to write a Haskell module with the following code:
module RectangleMover where
data Rectangle = Rectangle { xCoordinate :: Int
, yCoordinate :: Int
, width :: Int
, height :: Int
} deriving (Show)
move :: Rectangle -> Int -> Int -> Rectangle
-- Edit 1
move rec x y =
let rec' = { xCoordinate + x
, yCoordinate + y
}
return rec
To create a rectangle i would type:
let rec = Rectangle 10 10 20 30
But my question is now how to implement a function that "moves" this rectangle?
In C# or Java the call would be something like this: rec.move(20,20);
But how would this be written in Haskell?
This is unfortunately my first try with a functional programming language...
Edit 1: I added the code inside my function but still get a parse error at "xCoordinate + x" ...
Upvotes: 7
Views: 7122
Reputation: 532238
You just add the offsets to the corner:
move :: Rectangle -> Int -> Int -> Rectangle
move (Rectangle x y w h) dx dy = Rectangle (x + dx) (y + dy) w h
With record syntax, though, you can write it as
move :: Rectangle -> Int -> Int -> Rectangle
move r@(Rectangle {xCoordinate = x, yCoordinate=y}) dx dy = r {
xCoordinate = x + dx,
yCoordinate = y + dy }
Longer, but only because of the long names chosen for the two fields to update. You might further define a Point
type:
data Point = Point Int Int
movePoint :: Point -> Int -> Int -> Point
movePoint (Point x y) dx dy = Point (x + dx) (y + dy)
data Rectangle = Rectangle { corner :: Point, width :: Int, height :: Int }
move :: Rectangle -> Int -> Int -> Rectangle
move r@(Rectangle {corner=c}) dx dy = r { corner = movePoint c dx dy }
Upvotes: 11
Reputation: 32319
Given that this is your first time with Haskell, go with the record update answer already mentioned. However, for people googling this in the future, and for you too if you are feeling more ambitious (or for future learning), Haskell has this very popular and extremely powerful library called lens.
Here's how you can engineer a solution to your problem using it.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Rectangle = Rectangle { _xCoordinate :: Int
, _yCoordinate :: Int
, _width :: Int
, _height :: Int
} deriving (Show)
makeLenses ''Rectangle
move :: Rectangle -> Int -> Int -> Rectangle
move rect dx dy= rect
& xCoordinate +~ dx
& yCoordinate +~ dy
This solution may not seem more powerful initially, but when you start trying to update nested records, I assure you the advantage becomes clear.
Upvotes: 14
Reputation: 1220
Haskell values are immutable, so you want to return a new Rectangle
with the desired properties modified. It's simple, use "Record Update Syntax" like this let myNewRec = rec { yCoordinate = 20, xCoordinate = 20 }
Upvotes: 6