Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the special status of the 2-tuple?

Tags:

haskell

tuples

Reading Real World Haskell and the Typeclassopedia I get the impression that 2-tuples (a,b) can have very special roles in Haskell.

The first use that I came across is with lookup where we use a list of 2-tuples as a dictionary.

Then I also came across the fact that ((,) e) is an instance of a functor (but no other n-tuple), which makes sense for example in the above example of (key,value).

Now the most recent case - which is the one I actually want to ask about - is in chapter 4.3 of the Typeclassopedia. There it says that ((,) a) is an instance of Applicative if a is a monoid. When do you actually make use of that? What are applications where you use the Applicative instance of (a,b)?

like image 230
flawr Avatar asked Jun 27 '17 12:06

flawr


People also ask

Can a tuple have more than 2 elements?

We can do that by using a tuple containing two or more elements. A tuple is an ordered set of one or more elements, which can have different types. The number of elements in a particular tuple is fixed when that tuple is created.

How do you put two tuples together?

Concatenating and Multiplying TuplesConcatenation is done with the + operator, and multiplication is done with the * operator. Because the + operator can concatenate, it can be used to combine tuples to form a new tuple, though it cannot modify an existing tuple. The * operator can be used to multiply tuples.

What are tuples?

Tuple. Tuples are used to store multiple items in a single variable. Tuple is one of 4 built-in data types in Python used to store collections of data, the other 3 are List, Set, and Dictionary, all with different qualities and usage. A tuple is a collection which is ordered and unchangeable.

Does tuple allow duplicates in Python?

31.2 Python Collection Types Tuples allow duplicate members and are indexed. Lists Lists hold a collection of objects that are ordered and mutable (changeable), they are indexed and allow duplicate members. Sets Sets are a collection that is unordered and unindexed.


1 Answers

There's nothing preventing us from writing an instance for triples or arbitrary n-tuples:

instance Functor ((,,) a b) where
  fmap f (x,y,z) = (x,y,f z)

instance (Monoid a, Monoid b) => Applicative ((,,) a b) where
  pure z              = (mempty,        mempty,          z)
  (a,b,f) <*> (x,y,z) = (a `mappend` x, b `mappend` y, f z)

Pairs aren't special therefore in the sense that you can implement the instance for any n-tuple. But since those instances have to be written somewhere, it begs the question how far we should go. For example, Monoid instances are defined up to 5-tuples. It's certainly possible to write them for 10-tuples, but we're just copying boiler-plate code at that point.

That being said, pairs are special since their collection provide a natural way to describe a relation. One example is a dictionary, which relates a term and its definition:

dictionary :: [(String, String)]
dictionary =
  [("cat", "animal that likes strings; not Strings, though")
  ,("dog", "animal that likes you; yes you")
  ,("foo", "a strange word used by programmers in examples")
  ]

The other way to show that relation (if the first parts of all pairs would be unique) would be

partialDictionaryEntry :: String -> String

if we limit the input domain to "cat", "dog" and "foo", or

dictionaryEntry :: String -> Maybe String

which is exactly what \s -> lookup s dictionary would be. And with pairs you can model any other n-tuple:

(a,b,z)   = ((a,b),z)
(a,b,c,z) = ((a,b,c),z) = (((a,b),c),z)

In that sense they are the smallest container that provides this functionality. We can build all other tuples types from pairs. Heck, theoretically we don't even need to write our Applicative ((,,) a b) instance, since it's already provided for (,) (a,b) due to the Monoid instance.

That being said, why does it even have a Applicative instance? It's the simplest Writer implementation:

log :: (Show a) => a -> (String, a)
log x = (show x ++ "\n", x)

fivePlusThree = (+) <$> log 3 <*> log 5

main = do
  let (logs, result) = fivePlusThree
  putStrLn logs
  print result
3
5

8

This provides an easy way to add additional information to functions or values, although you will probably use Writer and its writer method, since they are more pleasant to use and provide a strict variant.

like image 64
Zeta Avatar answered Nov 15 '22 04:11

Zeta