I've got this
data Pair = P Int Double deriving Show
myP1 = P 1 2.0
getPairVal (P i d) = (i,d)
getPairVal' (P i d) = (,) i d
which work, both producing (1,2.0)
. Is there any way to make a straight (,) myP1
work? But then this would require some sort of "cast" I'm guessing.
data Pair2 = P2 (Int, Double) deriving Show
is a tuple version that is "handier" sort of
myP21 = (5,5.0)
So what would be the advantage of a product type like Pair
with or without a tuple type definition? I seem to remember SML having a closer relationship, i.e., every product type was a tuple type. In math, anything that's a "product" produces a tuple. Haskell apparently not.
CodePudding user response:
why shouldn't a straight (,) myP1 work?
Well, (,)
is a function that takes two values and makes a tuple out of them. P 1 2.0
is not two values: it is a single value of type Pair
, which contains two fields. But (,) (P 1 2.0)
is a well-typed expression: it has built the left half of a tuple, and needs one more argument for the right half. So:
let mkTuple = (,) (P 1 2.0)
in mkTuple "hello"
evaluates to
(P 1 2.0, "hello")
Why should we define types like Pair
instead of using tuples? user202729 linked to Haskell: Algebraic data vs Tuple in a comment, which is a good answer to that question.
But one other approach you could use would be to define a newtype
wrapping a tuple, so that you have a distinct named type, but the same runtime representation as a tuple:
newtype Pair2 = P2 (Int, Double) deriving Show
If you use newtype
instead of data
, you do get a simple conversion function, which you might choose to think of as a cast: Data.Coerce.coerce
. With that, you could write
myP21 = coerce (5, 5.0)
and vice versa. This approach is primarily used when you want new typeclass instances for existing types. If you need a new domain type composed of two values, I'd still encourage you to default to using a data
type with two fields unless there is a compelling reason not to.