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.
