user2277918
user2277918

Reputation: 247

Generalize the method signature of a function in haskell.

I am new to Haskell and trying to see how it works. I want to define a function in Haskell that could take a list of tuples, those tuples could be pair, 3-tuple, 4-tuple, 5-tuple and etc

functionY [(a,b)] 

Then I cannot call it with 3-tuple element like [(1,2,3),(2,3,4)]

functionY  [(1,2,3),(2,3,4)] // will complain 

How would I fix this? thanks

Upvotes: 1

Views: 208

Answers (1)

Chris Taylor
Chris Taylor

Reputation: 47382

Here is one approach, which is suitable if you don't mind writing a bit of boilerplate code. Conceptually, all that matters about an n-tuple is that it is a data structure with n slots that you can get access to. Every n-tuple for n >= m should have a method called get-m that gets whatever data is in the m'th slot. We can abstract that into a typeclass by using functional dependencies

{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}

class HasFirst a b | a -> b where
    get1 :: a -> b

class HasSecond a b | a -> b where
    get2 :: a -> b

Those type classes describe data that have a "first" and a "second" slot. We can write instances for 2-tuples and 3-tuples as follows

instance HasFirst (a,b) a where
    get1 (a,_) = a

instance HasSecond (a,b) b where
    get2 (_,b) = b

instance HasFirst (a,b,c) a where
    get1 (a,_,_) = a

instance HasSecond (a,b,c) b where
    get2 (_,b,_) = b

Now you can write a function that is generic over all data structures that have a "second" slot, for example

getSeconds :: HasSecond a b => [a] -> [b]
getSeconds = map get2

And use it as follows

>>> getSeconds [(1,2), (4,5)]
[2,5]
>>> getSeconds [(1,2,3), (4,5,6)]
[2,5]

Upvotes: 4

Related Questions