I want to convert list of tuples: [(2,2,2), (3,3,3), (4,4,4), (5,5,5)] to just list:
[2,2,2,3,3,3,4,4,4,5,5,5]
I try this
map (\(a,b,c,d)->a:b:c:d) listOfTuples
but get an error.
Prelude> map (\(a,b,c)->a:b:c) [(1,2,3), (5,6,7)]
<interactive>:1:37:
No instance for (Num [t])
arising from the literal `7' at <interactive>:1:37
Possible fix: add an instance declaration for (Num [t])
In the expression: 7
In the expression: (5, 6, 7)
In the second argument of `map', namely `[(1, 2, 3), (5, 6, 7)]'
Prelude>
How can I do it with lambda? And why my stuff does not work?
a:b:c:d is invalid because it's a : (b : (c : d)). (:) takes a list on the right-hand side and an element to prepend to it on the left-hand side, but d is another element, not (necessarily) a list. You probably mean a:b:c:d:[], which is the same as [a,b,c,d].
If you make that change, the code will run, and produce [[2,2,2], [3,3,3], [4,4,4], [5,5,5]], since map applies the function to each element of the list, and uses its result as the new element; that is, cannot change the structure of the list, only each element independently. If you want it flattened, you'll need to use concat (which has the type [[a]] -> [a], and flattens a list of lists):
concat (map (\(a,b,c,d) -> [a,b,c,d]) listOfTuples)
However, there is a ready-made composition of concat and map, which is more idiomatic to use:
concatMap (\(a,b,c,d) -> [a,b,c,d]) listOfTuples
This can also be done more succinctly with a list comprehension.
Assuming:
let listOfTuples = [(2,2,2), (3,3,3), (4,4,4), (5,5,5)]
then this list comprehension:
concat [[a,b,c] | (a, b, c) <- listOfTuples]
produces:
[2,2,2,3,3,3,4,4,4,5,5,5]
Related
I'm learning Haskell.
One of my standard techniques when learning a new language is to implement a Hello World genetic algorithm that attempts to generate a string via genetic algorithm techniques that matches some input string.
Due to my inexperience with Haskell (the closest thing I have to compare is Kotlin) I searched for an example code so I could match my existing understanding of basic genetic algorithm to the code and intuit some understanding of Haskell based on my already underway reading/research on the language.
I came across this tutorial: https://www.arcadianvisions.com/blog/2011/haskell-genetic-algorithm-hello-world.html
I transcribed it in atom after setting my environment up, each part I didn't understand I did a quick google, if I didn't understand the syntax/semantics after 15 minutes I would carry on transcribing with the intent to catch up later on those particular parts.
So, I understood most of the code, such as the order of function application, monads (think I'm nearly there with monads anyway), data types, function types, currying, type substitution etc. However, there were several bits of syntax/semantics that I haven't seen in my reading/researching and not sure what they do, but they appear a lot in the code example I linked to above. I'm hoping someone can explain them to me:
(++)
(:)
<$>
<*>
(,)
(x !!)
p#(info#())
I am assuming the () and <> are some special syntax and the stuff inside them is semantic? When I hover over them in atom (I'm using atom-haskell-ghc) I can see the type Functor f => Applicative (f :: * -> *) where <*> :: f (a -> b) -> f a -> f b which kind of looks like a monad, but I don't really understand the weird syntax/semantics on the consuming end. Should I think of these as just another function (with a weird infix alias?).
Here is a specific line exhibiting several of the examples from above:
mate :: RandomGen g => Gene -> Gene -> Rand g Gene
mate gene1 gene2 = (++) <$> flip take gene1 <*> flip drop gene2 <$> pivot
where pivot = getRandomR (0, length gene1 - 1)
A note on operators
In Haskell you can define a function that has as identifier a sequence of symbols wrapped between brackets, like for example (++) or (:) that is an operator that can be used both as a function, like (++) x y, and as an infix operator, like x ++ y. Behind the curtains, the Haskell compiler will convert the infix operator to a function call, so x ++ y is completely equivalent with (++) x y (except for the fact that operators have different precedence rules).
(++)
This is the append function: (++) :: [a] -> [a] -> [a] it takes two lists as input, and constructs a list of the same type of elements that contains the elements of the first list followed by the elements of the second list. For example:
(++) [1, 4, 2, 5] [1, 3, 0, 2] == [1, 4, 2, 5, 1, 3, 0, 2]
(:)
This is a constructor of the list type [a]. It has type (:) :: a -> [a] -> [a]. It takes as input an element and a list of elements (all of the same type), it construct a list that starts with the first element, followed by the elements of the second parameter. For example:
(:) 1 [4, 2, 5] = [1, 4, 2, 5]
(<$>)
You wrote in your question <$>, but as you perhaps figured out, that means that somewhere a function (<$>) :: Functor f => (a -> b) -> f a -> f b is defined.
A Functor is a typeclass. Several types in Haskell are functors. The easiest ones are a list [], and a Maybe. The (<$>) takes as input a function f :: a -> b, and a functor instance, for example a list [a]. It will then convert it to a functor instance [b]. How this is done, depends on how the Functor instance is implemented (the (<$>) for a Maybe has different semantics than one for []).
Although the analogy is not complete, you can see a Functor sometimes as a collection of elements (a Maybe basically is a collection of zero Nothing, or one Just x elements). It will then map the elements the collection contains by channeling these through the function, for example:
(+1) <$> [1, 4, 2, 5] == [2, 5, 3, 6]
(+1) <$> Nothing == Nothing
(+1) <$> (Just 2) == Just 3
(<*>)
This function (<*>) :: Applicative f => f (a -> b) -> f a -> f b is again somewhat hard to understand. It makes use of an Applicative type class.
An type that is an instance of Applicative has to implement two functions: pure :: Applicative a => a -> f a and (<*>) :: Applicative f => f (a -> b) -> f a -> f b (or the programmer can decide to instead implement liftA2, but let us ignore that here).
Again you can see Applicative (at least for popular instances) as a collection (like [] or Maybe). Here we thus take as input such collection of functions (all with type a -> b), and a collection of as. We then "multiply" these, in the sense that for instance for a list:
[f1, f2, ..., fm] <*> [x1, x2, ..., xn]
== [f1 x1, f1 x2, ..., f1 xn,
f2 x1, f2 x2, ..., f2 xn,
...,
fm x1, fm x2, ..., fm xn]
So that means for instance for Maybe that if the left operand is Nothing, or the right operand is Nothing, or both are Nothing, then this results in a Nothing, if both are Justs (so Just f <*> Just x), then we obtain a Just (f x):
Just f <*> Just x == Just (f x)
Just f <*> Nothing == Nothing
Nothing <*> Just x == Nothing
Nothing <*> Nothing == Nothing
(,)
This is the constructor of a 2-tuple: (,) :: a -> b -> (a,b) thus takes as input an a and a b, and it constructs an 2-tuple where the first item is the first parameter, and the second item is the second parameter. For example:
(,) 4 'a' == (4, 'a')
(x !!)
This is a section of an infix operator. You can use an infix operator, and for instance specify the left or the right part. In that case you thus construct a partially applied function. For example:
([1, 4, 2, 5] !!) == (!!) [1, 4, 2, 5]
(!! 2) == flip (!!) 2
So for the latter it thus means that we constructed a function that takes as input a parameter that will be filled in as left operand. So:
(!! 2) [1, 4, 2, 5] == (!!) [1, 4, 2, 5]
The (!!) :: [a] -> Int -> a function takes as input a list and an Int and it returns the element at that index (zero-based indices).
p#(info#())
In contrast to the above, the # is not a function or operator (well these are actually the same), but a keyword.
It is used in pattern matching to obtain a reference to both an pattern and for instance match subpatterns (or obtain references to subpatterns).
For instance, say we want to pattern match a 2-tuple, and we want to have a reference to the entire tuple, and the first element, we can use:
somefunction total#(left, _) = ...
So if we then call somefunction (4, 'a'), then this means that total will hold (4, 'a'), and left will hold 4.
These are mostly all regular functions.
The <> are not special syntax, just part of the function name.
The () are regular parenthesis which group things and define precedence like in most other languages, the important note is that when you want to refer to an operator function (like ++) it must be in parenthesis.
++ is the list concatenation function [1,2] ++ [3,4] = [1,2,3,4], or without using infix notation (++) [1,2] [3,4] = [1,2,3,4]
: is the 'cons' function, it prepends an element to a list 1 : [2, 3, 4] = [1,2,3,4] or (:) 1 [2, 3, 4] = [1,2,3,4] without infix notation.
<$> is an infix operator alias of fmap
<*> is the applicative application function
, is the tuple constructor (,) 1 2 = (1, 2)
!! is the list index function [1,2,3] !! 1 = 2. Note that since these are singly linked lists, indexing is an O(n) operation.
# is used to define an "as pattern". When pattern matching it allows you to give a name to a parameter, while also destructuring it with pattern matching. For example the pattern f (xs#[x1, x2]) matches a two element list, where you can use x1 and x2 to refer to the individual elements and xs to refer to the list as a whole
Imagine I have the following list:
lst :: [(Bool, Maybe Integer)]
lst = [(True, Just 3), (True, Nothing), (False, Just 12)]
Using the lens library, I want to extract the elements of the tuples, but I only want it to succeed when the second element is Just. I want some optic, split that works like this:
> lst ^.. folded.split (_1.to not) (_2._Just)
[(False, 3), (True, 12)]
I can implement split myself like this:
split :: Getting (First a) s a -> Getting (First b) s b -> Fold s (a, b)
split a b = folding (\x -> (,) <$> (x ^? a) <*> (x ^? b))
…which seems to work. However, this seems like I must be reinventing the wheel. Is there something already provided by the lens library that accomplishes this in an equally nice way?
The aside combinator takes a Prism that works over the second component of a tuple and returns a Prism that works over the whole tuple:
ghci> lst ^.. folded.aside _Just
[(True,3),(False,12)]
The resulting prism matches when the component is matched, otherwise it fails.
Combining it with to and bimap, we can reproduce your example:
ghci> lst ^.. folded.aside _Just.to (bimap not id)
[(False,3),(True,12)]
To work over the first component, we can use swapped:
ghci> [(Just 3,False)]^..folded.swapped.aside _Just.swapped
[(3,False)]
I'm very new to Haskell, and I decided to learn it some days ago, thanks to the haskell wikibook.
I'm reading at this moment the matching pattern for lists, but I can't understand the syntax for list.
Here's an example (from the wikibook) :
doubleList :: [Integer] -> [Integer]
doubleList [] = []
doubleList (n:ns) = (2 * n) : doubleList ns
I don't understand the part (n:ns). How should I read it ?
You can read it like this: (head:tail), so if you have [1, 2, 3] and you match it with (x:xs), then x will be bound to the first element in the list, 1, and xs will be bound to the rest of the list, in this case [2, 3].
(:) is an operator with type a->[a]->[a]. This means that it takes an item, and a list of those items, and returns another list of the same items. The output list is formed by prepending the input item to the input list.
Here is how you can use it
1:[2,3]
will return
[1,2,3]
Because the (:) appears on the left hand side of the definition, in your case, you are pattern matching, and the operator is being used to deconstruct the value, rather than build it.
For example, if we have
func (first:rest) = ....
and call it like this
func [1,2,3]
the following values would be assigned
first=1 --notice, this is type a
rest=[2,3] --notice, this is type [a]
Another tip that might help you understand is by looking at the definition of the list data type:
data [] a = [] | a : ([] a)
Note that Haskell makes special syntax rules just for the list type, normally [] is not a valid constructor. This definition is equivalent to
data List a = Empty | Cons a (List a)
Where
[] = Empty
(:) = Cons
You would pattern match on this as
doubleList :: List Int -> List Int
doubleList Empty = Empty
doubleList (Cons n ns) = Cons (2 * n) (doubleList ns)
If written using infix form:
doubleList (n `Cons` ns) = (2 * n) `Cons` doubleList ns
So now hopefully you can see the parallels between the two definitions. Haskell also provides the special syntax rule that
[1, 2, 3, 4] = 1:2:3:4:[]
Since the former is much easier to write and read. In fact, whenever you have a list literal like [1, 2, 3, 4] in your code, the compiler first converts it to 1:2:3:4:[] before converting your code into an executable.
I am starting to program with haskell. The program I am developing just sums the total of a list with two elementes, for example:
[("book",10),("cookies",2),("icecream",5)]
This should return "17". Here i my code:
total [] = []
total ([("c",e)]:y) = total y ++ [e]
But while running in GHCi it gives me this error:
<interactive>:80:8:
Couldn't match expected type `[([Char], a0)]'
with actual type `([Char], t0)'
In the expression: ("livro", 10)
In the first argument of `total', namely
`[("livro", 10), ("bolachas", 2), ("gelado", 5)]'
In the expression:
total [("livro", 10), ("bolachas", 2), ("gelado", 5)]
<interactive>:80:21:
Couldn't match expected type `[([Char], a0)]'
with actual type `([Char], t1)'
In the expression: ("bolachas", 2)
In the first argument of `total', namely
`[("livro", 10), ("bolachas", 2), ("gelado", 5)]'
In the expression:
total [("livro", 10), ("bolachas", 2), ("gelado", 5)]
<interactive>:80:36:
Couldn't match expected type `[([Char], a0)]'
with actual type `([Char], t2)'
In the expression: ("gelado", 5)
In the first argument of `total', namely
`[("livro", 10), ("bolachas", 2), ("gelado", 5)]'
In the expression:
total [("livro", 10), ("bolachas", 2), ("gelado", 5)]
This is probably very simple but as a beginner I was not able to solve this.
In the line:
total ([("c",e)]:y) = total y ++ [e]
the ([("c",e)]:y) does not do what you want. It matches a nonempty list in which the first element is also a list (because of the [...]) and in which that sublist has exactly one element, which is a pair whose first element equals "c". In order to match what you want, you need to write:
total ((c,e):y) = total y ++ [e]
However, this still won't do what you want, as it constructs a list of all of the e values in the input list. To sum them together, you need to do:
total [] = 0
total ((c,e):y) = total y + e
In addition to what #jwodder said, note that there's also another way to approach the problem. Instead of thinking /how/ you would compute the desired value, think about /what/ you do: you take the second element of every list item and then sum those elements up.
So you could start by writing two functions, one which takes a list of tuples yielding a list of all the second elements, and another computing the sum of a given list of numbers. A good start is to come up with the type signatures but defining the functions to evaluate to undefined:
-- Takes a list of tuples and returns all the second elements
getSecondElements :: [(String, Int)] -> [Int]
getSecondElements someList = undefined
-- Computes the sum of a given list of integers
sumOfIntList :: [Int] -> Int
sumOfIntList someInts = undefined
Using these, defining you function is straightforward:
total myList = sumOfIntList (getSecondElements myList)
You can run this through ghci and it'll type-check, which is a good sign. When you try to actually use total, you get an error though because the other two functions are just undefined.
Before you go and think about how to implement them, it's a good idea to see whether they exist already. You can search Hoogle for type signatures and it'll dig up functions matching that signature. The signature of getSecondElements doesn't yield any hits but the signature for the second yields a lot of hits, and most of those hits don't even talk about Int at all: Hoogle is smart enough to understand that functions which deal on arbitrary types of lists (say: length or head) may also be applicable. If you scroll down the page you'll see that there's an existing sum function already!
For the first function, you can repeat the process (recursively, if you like): in order to get all second-tuple-elements in a list, you first need a function which gets the second element of a tuple, like
getSecondElement :: (String, Int) -> Int
getSecondElement = undefined
and another function which applies that to all elements of a list. I'll skip ahead a bit: the standard function for getting the second element of a 2-tuple is called snd, and the function for collecting the results of calling a function on all elements of a list is called map. Try running
:t map snd
in ghci to see the type of map snd:
map snd :: [(a, b)] -> [b]
...which is a generalized version of the type of our getSecondElements function! So the two missing pieces are map snd and sum, which gives:
-- Takes a list of tuples and returns all the second elements
getSecondElements :: [(String, Int)] -> [Int]
getSecondElements someList = map snd someList
-- Computes the sum of a given list of integers
sumOfIntList :: [Int] -> Int
sumOfIntList someInts = sum
Instead of having two extra functions, you can also define total in terms of map snd and sum directly:
total someList = sum (map snd someList)
...which can be shortened to
total = sum . map snd
Not bad, is it?
Wondering if I could get some help writing this function. I am trying to create a function that inverts each "pair" in the list.
module Invert where
invert :: [(a,b)] -> [(b,a)]
invert [(a,b)] = [(b,a)]
When I enter invert [(3,1) (4,1) (5,1)]... it is supposed to give me [(1,3) (1,4) (1,5)... But it gives me...
*Invert> [(3,1) (4,1) (5,1)]
<interactive>:2:2:
The function `(3, 1)' is applied to two arguments,
but its type `(t0, t1)' has none
In the expression: (3, 1) (4, 1) (5, 1)
In the expression: [(3, 1) (4, 1) (5, 1)]
In an equation for `it': it = [(3, 1) (4, 1) (5, 1)]
Since lists are recursive data structures, you have to process a list recursively in order to swap all its elements, or use some higher order function that does the processing for you. If you define
invert [(a,b)] = [(b,a)]
it will only convert single-element lists, all other inputs will fail with an error!
Try to think about the input invert gets: It's either an empty list, or a non-empty lists. In the case of a non-empty list, you can swap the first element and convert the rest recursively.
(If you don't want to invert invert yourself, just use
invert = map swap
where swap is from Data.Tuple.)
Best way to solve this: split it into smaller problems, and either find library functions that solve those, or write your own. I always tell beginners that this is a superior exercise than trying to write a function like invert in just one part, because you should be learning the following three things:
How to split a problem into small, reusable pieces.
The standard library functions offered by the language.
How to use recursion to write small, reusable functions like the ones in the standard library.
In this case, we can split the problem into:
Inverting an individual tuple.
Applying a function to all elements of a list, and collecting the list of results.
The second one is just the common map function on lists, which comes with the standard library. You could try writing your own version of it; this sort of thing is always a good exercise for a beginner:
map :: (a -> b) -> [a] -> [b]
map f [] = ...
map f (x:xs) = ...
The first, as Petr points out, is the swap function from Data.Tuple. But we can write our own easily:
swap :: (a, b) -> (b, a)
swap (a, b) = (b, a)
And now, of course:
invert :: [(a, b)] -> [(b, a)]
invert = map swap
So you want to map a function over the list that's of type (a, b) -> (b, a). The function (,) has type b -> a -> (b,a). So if we flip it, we get a -> b -> (b, a). Now if we uncurry that, we get (a, b) -> (b, a):
invert = map (uncurry $ flip (,))
E.g.
> map (uncurry $ flip (,)) [(1, "a"), (2, "b")]
[("a",1),("b",2)]
As an aside, your patten matching doesn't match what you want. The definition
invert [(a,b)] = [(b,a)]
says "match a list with a single tuple in it". If you have a list with multiple tuples, the match will fail. Also, as Josh Lee pointed out, you need commas between tuples in your list.