Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Geometric point data type - tuple vs record?

Tags:

haskell

I can think of three ways to define a geometric point as an algebraic data type in Haskell. I want to define it as an algebraic data type for better documentation.

As a tuple type:

data Point a = Point a a

As a tuple:

data Point a= Point (a,a)

As a record:

data Point a = Point { pointx :: a, pointy :: a}

Which is better design/style and why?

like image 319
jarmond Avatar asked Mar 13 '23 10:03

jarmond


2 Answers

I think this depends mostly on your use-case at hand.

Though I'd never use data Point = Point (a, a), because this introduces one layer of indirection, which bloats the data structure - by two machine words - one for the Point and one for the pointer pointing to the tuple inside it.

Better use type Point a = (a,a) which is just an alias or newtype Point a = Point (a,a) which gets optimized away at compile time, so you have the benefits in this case.

The most flexible (for some definitions of flexible) is the last approach, though I'd call the records pr1 and pr2 for 'projection to the first/second component'. This approach also lends itself nicely to using lenses.

As @nikitavolkov said - it is a good idea to have strict data fields for performance reasons, but as I like records I'd ultimately go with

{-# LANGUAGE TemplateHaskell -#}
{-# LANGUAGE DeriveFoldable -#}
{-# LANGUAGE DeriveFunctor -#}
{-# LANGUAGE DeriveTraversable -#}
{-# LANGUAGE RecordWildCards #-}

import Control.Lens

data Point a = Point { _pr1 :: !a
                     , _pr2 :: !a
                     } deriving (..)
$(makeLenses ''Point)

which gets you the benefit of using norm Point{..} = sqrt (_pr1^2 + _pr2^2) with RecordWildCards and all the niceties of lenses.

Update (2017-09-03):

Just recently I found the strict package, which provides strict datatytpes as well as strict IO actions. One thing that stuck out to me was the following from Data.Strict.Maybe

Note that strict Maybe is not a monad since return ⊥ >>= f = ⊥ which is not necessarily the same as f ⊥.

Which I think is applicable to strict pairs as well - so keep that in mind when defining and/or using strict data types.

like image 63
epsilonhalbe Avatar answered Mar 17 '23 22:03

epsilonhalbe


Records are a controversial subject in Haskell. There is a consensus in the community that the existing implementation is suboptimal due to many reasons and things are being done to fix that.

Now, since the existing records implementation is suboptimal, many Haskellers tend to never use them. I'm one of those.

I would recommend going with the following:

{-# LANGUAGE DeriveFoldable, DeriveFunctor, DeriveTraversable #-}

data Point a =
  Point !a !a
  deriving (Functor, Foldable, Traversable)

This will give you free instances of some standard classes and strict data-structures are a recommended default.

like image 26
Nikita Volkov Avatar answered Mar 17 '23 21:03

Nikita Volkov