Accessing a Specific Element in a Tuple - haskell

Haskell-newbie reporting in.
Question is as follows:
In Haskell, we have fst and snd that return the first and the second elements of a 2-tuple. Why don't we have an easy way of accessing the i-th element from any tuple? Right now I have a 3-tuple, I want to read the 1st element and the only way of accomplishing this task is doing pattern-matching trickery. Why can't this be done easier? Or maybe there is some easy way?

What prevents the language from having the special construct you want is its design. The designers just didn't put this in, because it would complicate the language definition, which is quite minimalistic. fst and snd are library functions for the common case of pairs; you can define all the others yourself, or better, define record types for your data so that your data members have appropriate names.
(It may be that GHC has an extension to do this, but I haven't encountered one; check the docs or ask on the mailing list to be sure.)

Check out the tuple library on hackage. It has overloaded functions for various operations on tuples (up to a predefined size).

N-tuples are not a data structure for indexing via an Int key, instead, you should look at one indexed-biased data structures, such as arrays or finger-trees.
Now, one could imagine writing a typeclass for a family of tuple types providing an index operation, however, we already have arrays for that, and there's a lot of boilerplate necessary to make tuples of any type seamlessly provide this operation. The power gained isn't worth the effort.

Why can't this be done easier? Or maybe there is some easy way?
It can be easier using a recent alternative the
lens package. The Tuple module has selectors for up to 9 element tuples and it is straight forward to define more if needed.
> import Control.Lens
> data A = A deriving (Show)
> (1, '2', "3", A) ^. _1
1
> (1, '2', "3", A) ^. _2
'2'
> (1, '2', "3", A) ^. _3
"3"
> (1, '2', "3", A) ^. _4
A
You can also use the
lens package to update elements polymorphically, change type on update.
With and without infix operators:
> (1, '2', "3", A) & _1 .~ "wow"
("wow",'2',"3",A)
> set _1 "wow" (1, '2', "3", A)
("wow",'2',"3",A)
The github readme is a good place to start to find out more about the underlying theory as well as numerous examples.
Not just tuples
Similar syntax works for Traverables and Foldables, so Trees, Maps, Vectors, etc. For example if I had a list of tuples I can access the third tuple element at the 1 index by composing the element 1 to access the first index element with _3 to access the third tuple element.
[(1,2,3),(4,5,6),(7,8,9)] ^? element 1 . _3
Just 6

The question of an approach to doing this using template haskell was previously addressed here.
An example of its usage:
> $(sel 2 3) ('a','b','c')
'b'
> $(sel 3 4) ('a','b','c','d')
'c'
From here.

cabal update
cabal install tuple
ghci
λ> import Data.Tuple.Select
λ> sel3 (0, "1", 2) --select the third element

Nikita Volkov's new "record" library has a feature that appears to do what you want. Search for the heading "Tuples are records too!" on the linked page.
It looks like the library is still under development, so it may not be as easy to install and use right now as it will be in the future.

Related

Haskell. It is required to flatten the same elements in the list in the order they follow

How to remove identical duplicate items adjacent to the items in the list?
flattlst "aaaasssaaabbbssaaa"
--"asabsa"
I tried to do it through the "nub" function in the Data.List,
import Data.List
flattlst = nub
--flattlst"aaaasssaaabbbssaaa"
"asb" -- !!! It is wrong!!
"asabsa" -- !!The answer should be like this.
but that is not what I need. The "Nub" removes all the same elements, but I only need those that go in a row.Help me solve this problem.
nub will only yield an element, if it did not yield an equivalent element first. So nub indeed will emit "asb", since the 'a's, 's's and 'b's after that are already emitted.
What you can use is group :: (Eq a, Foldable f) => f a -> [NonEmpty a]. This will yield a non-empty list for each subsequence of equal elements. For example:
Prelude Data.List.NonEmpty> group "aaaasssaaabbbssaaa"
['a' :| "aaa",'s' :| "ss",'a' :| "aa",'b' :| "bb",'s' :| "s",'a' :| "aa"]
You still need to post-process this, such that for each NonEmpty element, you return the first element. I leave that as an exercise. Hint: you can use pattern matching for that.
Here's a naive approach that should work fine. It uses group from Data.List:
flattlst = map head . group
Most Haskell programmers, including me, generally warn against using head, as it will crash the program if used on an empty list. However, group is guaranteed to result in a list of non-empty lists*, so this should be OK.
*at least if the input is non-empty. I'm not sure what group does when used on an empty list - I suspect one way or another this will blowup, so add a special case for the empty list/string if that's important to avoid.

Filter through a list of 3(or greater)-tuples based on an element

Let's say I have a list of 3-tuples, like:
[(1,2,3),(4,5,6),(7,8,9)]
What would be a way to filter through these if I wanted to, say, find every item where its first element is 1. filter ((==1).fst) can't be used as the tuples' lengths are not equal to 2. I've had some ideas but I can't seem to progress them into workable code, so I wanted to see if there were a better solution someone more knowledgable with this language could suggest.
With static typing, the simplest way is probably to type all the commas manually:
filter (\(x,_,_) -> x == 1) [(1,2,3),(4,5,6),(7,8,9)]
(You can try to automate this, e.g. writing a generic version of fst as a class method, but then you'll need to manually state that every tuple size is an instance of this class.)
You can use the lens library, which provide a Lens to operate on tuple.
import Control.Lens
filter ((== 1) . (^. _1)) [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
Lens use type classes like Field1 Field2 ... to make code above possible.

Haskell # type annotation [duplicate]

I've come across a piece of Haskell code that looks like this:
ps#(p:pt)
What does the # symbol mean in this context? I can't seem to find any info on Google (it's unfortunately hard to search for symbols on Google), and I can't find the function in the Prelude documentation, so I imagine it must be some sort of syntactic sugar instead.
Yes, it's just syntactic sugar, with # read aloud as "as". ps#(p:pt) gives you names for
the list: ps
the list's head : p
the list's tail: pt
Without the #, you'd have to choose between (1) or (2):(3).
This syntax actually works for any constructor; if you have data Tree a = Tree a [Tree a], then t#(Tree _ kids) gives you access to both the tree and its children.
The # Symbol is used to both give a name to a parameter and match that parameter against a pattern that follows the #. It's not specific to lists and can also be used with other data structures.
This is useful if you want to "decompose" a parameter into it's parts while still needing the parameter as a whole somewhere in your function. One example where this is the case is the tails function from the standard library:
tails :: [a] -> [[a]]
tails [] = [[]]
tails xxs#(_:xs) = xxs : tails xs
I want to add that # works at all levels, meaning you can do this:
let a#(b#(Just c), Just d) = (Just 1, Just 2) in (a, b, c, d)
Which will then produce this: ((Just 1, Just 2), Just 1, 1, 2)
So basically it's a way for you to bind a pattern to a value. This also means that it works with any kind of pattern, not just lists, as demonstrated above. This is a very useful thing to know, as it means you can use it in many more cases.
In this case, a is the entire Maybe Tuple, b is just the first Just in the tuple, and c and d are the values contained in the first and second Just in the tuple respectively
To add to what the other people have said, they are called as-patterns (in ML the syntax uses the keyword "as"), and are described in the section of the Haskell Report on patterns.

What makes a good name for a helper function?

Consider the following problem: given a list of length three of tuples (String,Int), is there a pair of elements having the same "Int" part? (For example, [("bob",5),("gertrude",3),("al",5)] contains such a pair, but [("bob",5),("gertrude",3),("al",1)] does not.)
This is how I would implement such a function:
import Data.List (sortBy)
import Data.Function (on)
hasPair::[(String,Int)]->Bool
hasPair = napkin . sortBy (compare `on` snd)
where napkin [(_, a),(_, b),(_, c)] | a == b = True
| b == c = True
| otherwise = False
I've used pattern matching to bind names to the "Int" part of the tuples, but I want to sort first (in order to group like members), so I've put the pattern-matching function inside a where clause. But this brings me to my question: what's a good strategy for picking names for functions that live inside where clauses? I want to be able to think of such names quickly. For this example, "hasPair" seems like a good choice, but it's already taken! I find that pattern comes up a lot - the natural-seeming name for a helper function is already taken by the outer function that calls it. So I have, at times, called such helper functions things like "op", "foo", and even "helper" - here I have chosen "napkin" to emphasize its use-it-once, throw-it-away nature.
So, dear Stackoverflow readers, what would you have called "napkin"? And more importantly, how do you approach this issue in general?
General rules for locally-scoped variable naming.
f , k, g, h for super simple local, semi-anonymous things
go for (tail) recursive helpers (precedent)
n , m, i, j for length and size and other numeric values
v for results of map lookups and other dictionary types
s and t for strings.
a:as and x:xs and y:ys for lists.
(a,b,c,_) for tuple fields.
These generally only apply for arguments to HOFs. For your case, I'd go with something like k or eq3.
Use apostrophes sparingly, for derived values.
I tend to call boolean valued functions p for predicate. pred, unfortunately, is already taken.
In cases like this, where the inner function is basically the same as the outer function, but with different preconditions (requiring that the list is sorted), I sometimes use the same name with a prime, e.g. hasPairs'.
However, in this case, I would rather try to break down the problem into parts that are useful by themselves at the top level. That usually also makes naming them easier.
hasPair :: [(String, Int)] -> Bool
hasPair = hasDuplicate . map snd
hasDuplicate :: Ord a => [a] -> Bool
hasDuplicate = not . isStrictlySorted . sort
isStrictlySorted :: Ord a => [a] -> Bool
isStrictlySorted xs = and $ zipWith (<) xs (tail xs)
My strategy follows Don's suggestions fairly closely:
If there is an obvious name for it, use that.
Use go if it is the "worker" or otherwise very similar in purpose to the original function.
Follow personal conventions based on context, e.g. step and start for args to a fold.
If all else fails, just go with a generic name, like f
There are two techniques that I personally avoid. One is using the apostrophe version of the original function, e.g. hasPair' in the where clause of hasPair. It's too easy to accidentally write one when you meant the other; I prefer to use go in such cases. But this isn't a huge deal as long as the functions have different types. The other is using names that might connote something, but not anything that has to do with what the function actually does. napkin would fall into this category. When you revisit this code, this naming choice will probably baffle you, as you will have forgotten the original reason that you named it napkin. (Because napkins have 4 corners? Because they are easily folded? Because they clean up messes? They're found at restaurants?) Other offenders are things like bob and myCoolFunc.
If you have given a function a name that is more descriptive than go or h, then you should be able to look at either the context in which it is used, or the body of the function, and in both situations get a pretty good idea of why that name was chosen. This is where my point #3 comes in: personal conventions. Much of Don's advice applies. If you are using Haskell in a collaborative situation, then coordinate with your team and decide on certain conventions for common situations.

What does the "#" symbol mean in reference to lists in Haskell?

I've come across a piece of Haskell code that looks like this:
ps#(p:pt)
What does the # symbol mean in this context? I can't seem to find any info on Google (it's unfortunately hard to search for symbols on Google), and I can't find the function in the Prelude documentation, so I imagine it must be some sort of syntactic sugar instead.
Yes, it's just syntactic sugar, with # read aloud as "as". ps#(p:pt) gives you names for
the list: ps
the list's head : p
the list's tail: pt
Without the #, you'd have to choose between (1) or (2):(3).
This syntax actually works for any constructor; if you have data Tree a = Tree a [Tree a], then t#(Tree _ kids) gives you access to both the tree and its children.
The # Symbol is used to both give a name to a parameter and match that parameter against a pattern that follows the #. It's not specific to lists and can also be used with other data structures.
This is useful if you want to "decompose" a parameter into it's parts while still needing the parameter as a whole somewhere in your function. One example where this is the case is the tails function from the standard library:
tails :: [a] -> [[a]]
tails [] = [[]]
tails xxs#(_:xs) = xxs : tails xs
I want to add that # works at all levels, meaning you can do this:
let a#(b#(Just c), Just d) = (Just 1, Just 2) in (a, b, c, d)
Which will then produce this: ((Just 1, Just 2), Just 1, 1, 2)
So basically it's a way for you to bind a pattern to a value. This also means that it works with any kind of pattern, not just lists, as demonstrated above. This is a very useful thing to know, as it means you can use it in many more cases.
In this case, a is the entire Maybe Tuple, b is just the first Just in the tuple, and c and d are the values contained in the first and second Just in the tuple respectively
To add to what the other people have said, they are called as-patterns (in ML the syntax uses the keyword "as"), and are described in the section of the Haskell Report on patterns.

Resources