1

Suppose I have these definitions of a data in Haskell.

data Point a = Point a a
data Piece a = One a | Two a

and I want to have one function like

place :: Num a => Piece (Point a) -> Point a
place (Piece x) = x

how do I do this since haskell doesn't allow functions of that particular form.

Solution

The problem was my data definition (many years of empirical programming is interfering here...). I wanted my Piece data to effectively be 2 different things, a Piece and also a kind of piece, I tried to achieve this with inheritance which was just a bad approach. Separating data in the following way solved the problem.

data PieceKind = One | Two | ... | n
data Piece a b = Piece a PieceKind

This way my Piece effectively has two attributes "a" (in my case this is a position of a piece) and also PieceKind, this way I was able to write the place function without having to repeat it for every kind of piece in the following way:

place :: Num a => Piece (Point a) PieceKind -> Point a
place (Piece x _) = x

In addition I was also able to write functions for a particular kind of a Piece:

place :: Num a => Piece (Point a) PieceKind -> Point a
place (Piece _ One) = ...

and this is what I really wanted.

4
  • Is your intent to have it work like place (One x) = x; place (Two x) = x ? Commented Feb 4, 2017 at 9:35
  • Yes, instead of having one function for every constructor I want to have just one function for all of them. Commented Feb 4, 2017 at 9:47
  • Make your question self-contained by defining Point. Commented Feb 4, 2017 at 10:00
  • @Jubobs updated my question Commented Feb 4, 2017 at 10:16

1 Answer 1

2

Use a record for the common fields

data Piece a = One { place :: a } | Two { place :: a }
-- place automatically defined

Or factorize the common data

data Piece a = Piece Bool a

place :: Piece a -> a
place (Piece _ x) = x

-- optionally:
pattern One x = Piece False x
pattern Two x = Piece True  x

In the general case, instead of Bool you have to use a custom sum type to express the rest of the factorization. E.g.

data T a = A Int a | B Bool a

becomes

data T a = T (Either Int Bool) a
-- optionally:
pattern A n x = T (Left n)  x
pattern B b x = T (Right b) x

Template Haskell could also solve this, but it is overkill, IMO.

Sign up to request clarification or add additional context in comments.

8 Comments

Still not entirely what I was expecting, your suggestion is ok if you have a few constructors but what if you have 10 and they all have a shared function, then with your solution I would have to repeat { place :: a } 10 times. There must be a better way.
@DovydasRupšys Not if you factor your data correctly, as suggested below.
@DovydasRupšys I don't think there's a much easier way. You could autogenerate the function you want with Template Haskell, which can generate code for you as in a macro system, but setting it up for this would require some care. If you have a very large amount of types/constructors, it could be worth it, but otherwise it requires too much effort.
I'm failing to see how the above factorization applies, I don't even see where the factorization is happening. Is the meaning of factorization the same in functional languages as it is in empirical?
Wait, nvm I think I get it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.