Understanding the map function with function composition - haskell

I have the following Haskell expression:
let increment x = 1 + x
in \xs -> map chr (map increment (map ord xs))
I know that the above expression takes a list, and applies the ord function to each element in the list. For a list of chars, the result would be a list of integers (the ASCII value). The increment function then increments each integer in the list by 1. The chr function then converts each integer back into its corresponding character.
And I also have the following expression:
map chr . map (1+) . map ord
I am trying to figure out whether the above is equivalent to the first expression.
However when I tried the above expression in GHCI, I got an error:
map chr . map (1+) . map ord ['a', 'b', 'c', 'd', 'e']
I am not sure why the expression didn't work. Since function composition is used, wouldn't the expression be evaluated as:
(map chr (map (1+) (map ord ['a', 'b', 'c', 'd', 'e'])))
With map (1+) getting a list as a result of map ord, and map chr getting a list as a result of map (1+)?

Operators (defined as functions with no alphanumeric characters in their name, which are used in infix style) have lower precedence than other functions in Haskell. Therefore your expression:
map chr . map (1+) . map ord ['a', 'b', 'c', 'd', 'e']
is parsed as:
(map chr) . (map (1+)) . (map ord ['a', 'b', 'c', 'd', 'e'])
And this doesn't make any sense - the . operator combines 2 functions, and map ord ['a', 'b', 'c', 'd', 'e'] is not a function, but a list of numbers.
But there are still better alternatives to your correct version with all the nested parentheses. What you want to do is start with the list of characters, and successively map 3 functions over it. That, by definition of function composition, is the same as applying the composition of the 3 map s to it, ie:
(map chr . map (1+) . map ord) ['a', 'b', 'c', 'd', 'e']
which as #chi points out below, would often be written like this, using the function application operator $ (which has lower precedence than any other operator) to avoid the need for any parentheses:
map chr . map (1+) . map ord $ ['a', 'b', 'c', 'd', 'e']
And, because map f . map g is always the same as map (f . g) (this should be obvious when you stop to think about what these expressions mean - it's also the fundamental law the map operation must satisfy in order to make the list type into a Functor), this can be alternatively written as:
map (chr . (1+) . ord) ['a', 'b', 'c', 'd', 'e']
In my opinion this is the best and most readable version.
Although even better, as #chi again points out, is to use that chr . (1+) . ord is equivalent to succ, the built-in function for getting the "next" value of a type that can be enumerated. So you can just write map succ ['a', 'b', 'c', 'd', 'e']

Related

99 Haskell Questions #9

https://wiki.haskell.org/99_questions/1_to_10
regarding the solution to Question 9
pack :: Eq a => [a] -> [[a]] -- problem 9
pack [] = []
pack (x:xs) = (x:first) : pack rest
where
getReps [] = ([], [])
getReps (y:ys)
| y == x = let (f,r) = getReps ys in (y:f, r)
| otherwise = ([], (y:ys))
(first,rest) = getReps xs
--input
pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a','a', 'd', 'e', 'e', 'e', 'e']
--output
["aaaa","b","cc","aa","d","eeee"]
whats going on here: (x:first), i can see that rest is being passed pack, but i don't understand the bit before that.
getReps is a function specific to each iteration of pack, as it closes over the current values of x and xs.
The first call to pack "aaaabccaadeeee" results in a call to getReps "aaabccaadeeee". getReps will return ("aaa", "bccaadeeee"). Effectively, pack self splits off the first 'a' (the value of x), and getReps separates the rest of the 'a's from the value of xs. Thus, the final "value" of pack "aaaabccaadeeee" is ('a':"aaa") : pack "bccaadeeee".

Transforming a flattened list into a nested list of length 3 [duplicate]

This question already has answers here:
Grouping a list into lists of n elements in Haskell
(4 answers)
Closed 4 years ago.
Given a flattened list in Haskell:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
and n=3
how can I change the list to:
[['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]
preferably a solution where n is a variable
It is a good example show how to use of unfoldr as:
f n = unfoldr (\xs->if null xs then Nothing else Just (take n xs, drop n xs))
Note that it can accept infinite list as:
take 4 $ f 3 [1..]
gives
[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]
for characters
take 4 $ f 3 ['a'..]
gives
["abc","def","ghi","jkl"]

List of strings to list of chars - [[Char]] to [Char] haskell

I need to convert list like this ["a","b","c"] to this ['a','b','c']. The thing is i used
splitOn
function which gave me [[Char]] from [Char]. Is there a way to convert this list of string to list of char? Assuming strings are length of 1 of course.
Yes, you can use concat :: [[a]] -> [a]:
Prelude> concat ["a","b","c"]
"abc"
Since a String is a type alias for [Char], so "abc" is short for ['a', 'b', 'c']:
Prelude> concat ["a","b","c"] == ['a', 'b', 'c']
True
concat ["a", "b", "c"] will give you the string "abc" which is the same as ['a', 'b', 'c']

Clean list comprehension for sampling from list of lists?

I have a lists of list in Haskell. I want to get all the possibilities when taking one element from each list. What I have currently is
a = [ [1,2], [10,20,30], [-1,-2] ] -- as an example
whatIWant = [ [p,q,r] | p <- a!!0, q <- a!!1, r <- a!!2 ]
This does what I want. However, this is obviously not very good code, and I'm looking for a better way of writing the list comprehension so that no index number (0,1,2) shows up in the code... which is where I'm stuck.
How can I do this?
Using a function (which uses a list comprehension inside), my solution is
combinations :: [[a]] -> [[a]]
combinations [] = []
combinations [l] = map (\ x -> [x]) l
combinations (x:xs) = combine (combinations [x]) (combinations xs)
where combine a b = [ p ++ q | p <- a, q <- b ]
Example:
*Main> combinations [[1, 2, 3], [4, 5, 6]]
[[1,4],[1,5],[1,6],[2,4],[2,5],[2,6],[3,4],[3,5],[3,6]]
*Main> combinations [['a', 'b', 'c'], ['A', 'B', 'C'], ['1', '2']]
["aA1","aA2","aB1","aB2","aC1","aC2","bA1","bA2","bB1",...
"bB2","bC1","bC2","cA1","cA2","cB1","cB2","cC1","cC2"]
Edit: of course you can use the sequence function, as was suggested in the comments:
*Main> sequence [['a', 'b', 'c'], ['A', 'B', 'C'], ['1', '2']]
["aA1","aA2","aB1","aB2","aC1","aC2","bA1","bA2","bB1",...
"bB2","bC1","bC2","cA1","cA2","cB1","cB2","cC1","cC2"]
this is obviously not a good code
This is about the best way you can do it, given your constraint that the input is a list of lists.
If you use a different type, e.g. a triple of lists, then you can index structurally. E.g.
Prelude> let x#(a,b,c) = ( [1,2], [10,20,30], [-1,-2] )
Lets you write:
Prelude> [ (p,q,r) | p <- a , q <- b , r <- c ]
[(1,10,-1),(1,10,-2),(1,20,-1)
,(1,20,-2),(1,30,-1),(1,30,-2)
,(2,10,-1),(2,10,-2),(2,20,-1)
,(2,20,-2),(2,30,-1),(2,30,-2)]
Lesson: to avoid indexing, use a type whose structure captures the invariant you want to hold. Lift the dimension of the data into its type.

Haskell get character array from string?

Is it possible if given a string I could get each character composing that string?
In Haskell, strings are just (linked) lists of characters; you can find the line
type String = [Char]
somewhere in the source of every Haskell implementation. That makes tasks such as finding the first occurence of a certain character (elemIndex 'a' mystring) or calculating the frequency of each character (map (head &&& length) . group . sort) trivial.
Because of this, you can use the usual syntax for lists with strings, too. Actually, "foo" is just sugar for ['f','o','o'], which in turn is just sugar for 'f' : 'o' : 'o' : []. You can pattern match, map and fold on them as you like. For instance, if you want to get the element at position n of mystring, you could use mystring !! n, provided that 0 <= n < length mystring.
Well, the question does say he wants an array:
import Data.Array
stringToArray :: String -> Array
stringToArray s = listArray (0, length s - 1) s
The string type is just an alias for [Char] so you don't need to do anything.
Prelude> tail "Hello"
"ello"
Prelude> ['H', 'e', 'l', 'l', 'o']
"Hello"
Prelude> "Hello" !! 4
'o'

Resources