From Thinking Functionally with Haskell, pg 67:
[...] list comprehensions are translated into equivalent definitions in
terms of map and concat. The translation rules are:
[e | True] = [e]
[e | q] = [e | q, True]
[e | b, Q] = if b then [e | Q] else []
[e | p <- xs, Q] = let ok p = [e | Q]
ok _ = []
in concat (map ok xs)
The author nowhere defines e, q, Q, or b. I take it that the first means "expression," but I've never seen the others before. Could someone please enlighten me?
This translation comes straight out of the official Haskell Report, which has this additional sentence:
where e ranges over expressions, p over patterns, l over list-valued expressions, b over boolean expressions, decls over declaration lists, q over qualifiers, and Q over sequences of qualifiers. ok is a fresh variable. The function concatMap, and boolean value True, are defined in the Prelude.
If you wonder what any of those terms means, the Report has further details.
I would guess that:
e is any expression, as you say
q is any expression with type Bool
b is also any expression with type Bool (this seems a bit strange, though, perhaps I'm wrong...)
p is any pattern. For example, Right x, Just _, x#(y,z)
Q is a bunch of list comprehension elements separated by commas. By "list comprehension element" I mean either guards (i.e. expressions of type Bool) or pattern matches, e.g x <- xs, Right x <- xs.
Related
As the title implies, I am unsure about the difference between square brackets and parentheses in regard to lists.
Two versions of Haskell's insert defined, one using square brackets, the other using parentheses:
insert' :: Int -> [Int] -> [Int]
insert' y [] = [y]
insert' y (x:xs) | y <= x = y:x:xs | otherwise = x : insert' y xs
----
insert' y [x:xs] | y <= x = y:x:xs | otherwise = x : insert' y xs
What is the reason the second definition of insert' doesn't work?
The error message it gives, for anyone wondering:
test.hs:3:12: error:
• Couldn't match expected type ‘Int’ with actual type ‘[Int]’
• In the pattern: x : xs
In the pattern: [x : xs]
In an equation for ‘insert'’:
insert' y [x : xs]
| y <= x = y : x : xs
| otherwise = x : insert' y xs
|
3 | insert' y [x:xs] | y <= x = y:x:xs | otherwise = x : insert' y xs
|
As in almost all other languages, parentheses in Haskell don't really do anything. They help the parser know which things you intended to group together, and that's it; they don't change the meaning of the thing that's inside them, and if the parser could magically guess which way you intended to group things at every choice point we wouldn't need them at all. So all of these patterns behave exactly the same:
x
(x)
((x))
(((((((((x)))))))))
All of these patterns are also exactly the same:
x:xs
(x:xs)
((x:xs))
(((((((((x:xs)))))))))
Sometimes we must use one of the later ones -- like (x:xs) -- instead of the first one -- x:xs -- to inform the parser that we intended these things to be grouped together. But the parentheses don't otherwise change anything about what the pattern means.
Square brackets, on the other hand, are used for constructing lists. They have an actual run-time meaning: they allocate a new data structure in memory and initialize it. For example, 3 is a number, but [3] is a list with a single element, [3,4] is a list with two elements, [[3]] is a list of lists, and so on. The same behavior applies to patterns:
x -- match anything (even a list!) and bind x to its value
[x] -- match a list with a single element, and bind x to that element's value
[x,y] -- match a list with two elements, and bind x and y to those elements' values
[[x]] -- match a nested list; the outer and inner lists both have one element; bind x to the first element's first element
Now we can address your specific example. The pattern x:xs is a pattern that matches any list with at least one element, binding x to that first element and xs to the rest of the list. The pattern (x:xs) does exactly the same thing. The pattern [x:xs], on the other hand, matches a list with exactly one element, because there are square brackets; the only element of that list is then matched against the pattern x:xs, with the behavior described above.
One consequence of this is that x:xs can match lists with any type of element -- say, Int -- but [x:xs] can only match lists whose elements are lists.
(x:xs) as a pattern will match any non-empty list with x its head and xs its tail.
[x:xs] as a pattern will match a singleton list -- a list containing exactly one item -- which is a non-empty list, matching the pattern (x:xs). The pattern [x:xs] is in fact equivalent to the pattern [(x:xs)]. It is a nested pattern, and Haskell allows that. The outer pattern matches a singleton list, and the inner pattern matches a non-empty list. The parentheses in this position are optional.
That's why your second definition implies the type of the second argument is [[a]], but you've declared it to be [Int]. And Int can't match [a]. (That a is also determined to be an Int, since you compare x and y, and y the first argument is declared to be an Int, but that doesn't change anything).
[ [a] ]
[ Int ]
----------------
***mismatch***
I'm learning Haskell with Miran Lipovaca's "Learn You a Haskell for Great Good!". In page 82 it says
If a pattern match fails, the list comprehension will just move on to the next element, and the element that failed won’t be included in the resulting list.
Example:
ghci> let xs = [(1,3),(4,3),(2,4),(5,3),(5,6),(3,1)]
ghci> [a+b | (a, b) <- xs]
[4,7,6,8,11,4]
My question is how does a pattern match fail?
What does he mean by that? I really don't get it. It could be because of my weak english. I please you for an example because I think the book doesn't give any example for failing pattern match.
I thought about something like if the list contains a type that couldn't be processed by the list comprehension then it moves to the next element but if I change the list in this way:
let xs = [(1,3),(4,3),(2,4),(5,3),True,(5,6)]
Then it doesn't even compile because it "couldn't match expected type"...
Here are a few cases of failing pattern matching in list comprehensions, demoed in GHCi:
Prelude> [ () | True <- [True, False,True] ]
[(),()]
Prelude> [ x | (x, True) <- [(1,True), (2,False), (3,True)] ]
[1,3]
Prelude> [ x+1 | Left x <- [Left 1, Right "Hello", Right "world", Left 2] ]
[2,3]
Note that some patterns can never fail, e.g. x, (x,y), or (x,(a,b),z). This is because they match types having only a constructor, which has to match being the only one.
In general, pattern matching involves multiple branches, e.g.
case someValue of
Left x -> ...
Right y -> ...
foo Nothing = ...
foo (Just x) = ...
In these cases, if we forget to handle a constructor, we get a runtime error when that case occurs. (Turning on warnings helps in avoiding this!).
In list comprehensions generators p <- ..., instead, we can only specify one pattern. However, a special rule applies: failure of pattern matching is not an error, but is simply ignored.
That's not an example of pattern-match failure (the tuple pattern matches always). This would be an example:
Prelude> xs = [Just (1,3), Just (4,3), Nothing, Just (5,3), Nothing]
Prelude> [a+b | Just (a, b) <- xs]
[4,7,8]
Here, the pattern Just (a, b) matches only the elements Just (1,3), Just (4,3) and Just (5,3), but not the Nothings, so these positions just don't turn up in the final list.
I am new to haskell. Can someone explain how I can interpret this line of code in haskell :
filter (\(_, (varible1, _)) -> variable1 `notElem` [something1, something2])
-- Filter a list...
filter
-- ...of nested tuples where the first element of the second element of the tuple...
(\(_, (variable1, _)) ->
-- ...is not an element of [something1, something2]
variable1 `notElem` [something1, something2])
(_, (varible1, _)) deconstructs a nested tuple, and names one of the elements. Look up deconstruction to understand what's going on there.
Let's start at the beginning.
\p -> e
is a lambda abstraction (an anonymous function) where p is a pattern and e is an expression that may use variables that appear in p.
(_, (variable1, _))
is a pattern constructed from the constructor (,), which constructs pairs. Here are some pairs:
(1, 2)
("Hello", "world!")
(1, (2, 3))
Here are some patterns which match pairs, used in lambda abstractions.
\(x, y) -> x
\(x,(y,z)) -> y
The second pattern matches a pair like (1, (2, 3)) and gives the first element of the second element. In this case, it would give 2. Its shape is like the pattern in your question, but what about the _ in your pattern?
_ is a valid variable name (variables can begin with underscores or lower-case letters). It is used to mean "a variable we don't use". The pattern (_, (y, _)) is like the pattern (x, (y, z)) except the only variable that has a name is y. Normally, you aren't allowed to reuse variable names in patterns. (x,x) is in invalid pattern, for instance. You are allowed to reuse _ though because Haskell knows you intend to throw that value away.
Now we can understand the expression
\(_, (variable1, _)) -> variable1
It is a function of type (a, (b, c)) -> b which takes a pair whose second element is itself a pair and gives the first element of the second element.
Now we need to understand
variable1 `notElem` [something1, something2]
To understand this expression, we need to know what the backticks do. Surrounding an identifier in backticks turns it into an infix operator. Infix operators are usually spelled with symbols, like x + y and xs ++ ys. The backticks let us convert normal identifiers, like notElem, into infix operators. This means that the above expression is the same as
notElem variable1 [something1, something2]
notElem is a function which takes an item and a list of items of the same type and gives True if the item does not appear in the list and False otherwise. It is the opposite of the elem test for membership.
Finally, filter. filter p xs is a function that takes a predicate p (i.e., a function which returns a Bool) and uses it to filter the list xs. filter gives a new list where elements (call them x) are included if p x is true. This filters the list of xs and gives a new list whose elements are those for which the predicate is true. For example,
> filter even [1,2,3,4]
[2,4]
So, we have
filter -- filter a list
(\(_, (variable1, _)) -- by matching on the first element
-- of the second element of a pair
-- and calling it 'variable1'
-> variable1 `notElem` [something1, something2])
-- and giving `True` if the element
-- is neither 'something1' nor 'something2'
This gives a function which takes a list of pairs whose second element is a pair and filters it to a list of pairs whose second element is a pair whose first element is neither something1 nor something2.
We can apply it, calling it f below:
f = filter (\(_, (varible1, _)) -> variable1 `notElem` [something1, something2])
> f [(1,(something1,2)), (1,(something3,3))]
[(1,(something3,3))]
I am curious whether or not using list comprehension in place of recursion is possible for the following example.
The function replaceFirst that takes in an an element and a list and replaces the first occurrence of the element from the list.
This can be done using recursion as follows:
replaceFirst _ [] = []
replaceFirst elem y (x:xs) | x==y = (elem:xs)
| otherwise = x:replaceFirst elem y xs
My question is, can this recursive function, or a similar recursive function that operates on the first occurrence of an element in a list, be replaced with a list comprehension function? Why or why not? (I am more concerned with the reasoning than the actual code).
List comprehensions are syntactic sugar for various forms of map, filter, and concatMap. If your recursive function can be described in terms of these, then you can rewrite it to a list comprehension. They can't short circuit, as you do above, nor can they pass accumulating state.
Your replaceFirst would seem to require an accumulator to "tell" later elements in the list about the appearance of earlier elements. I think this makes it difficult or impossible to write using only list comprehension syntax.
List comprehension, inspired by leftaroundabout:
replaceFirst elem y xs = [a | let b = break (==y) xs
c = if not (null $ snd b)
then fst b ++ [elem] ++ tail (snd b)
else fst b
, a <- c]
I am trying to build a list of tuples. Input is a list of tuples [([char], int1, int2), ...] and the output is the list of tuples such that [([char], int1, int2, (int1/int2)), ...]. I know that this code below is wrong because I think it is building a list of lists of tuples [[(),(),(),()], [(),(),(),()]].
Code:
{- take a list of labels, values, and weights and return list of labels and fractions -}
fraclist [] = []
fraclist x = [ (y,r,q,z) : y <- first (head x) | r <- scnd (head x) | q <- last (head x) | z <- r/q ] : fraclist tail x
{- helper func to get values from tuples -}
frst (a,b,c) = a
scnd (a,b,c) = b
last (a,b,c) = c
How might I get the proper output form as described? Also, how might I output the list of tuples ordered such that the z's are in descending order?
This code doesn't compile (syntax errors), but after fixing that (I'd recommend reading up on the syntax of list comprehensions (','s vs. '|'s)) and making some other changes:
used a list comprehension, which takes care of the base case and the mapping over the list -- so I was able to eliminate fraclist [] = [] and the head/tail/: business
used pattern matching to pull the values out of the input tuples -- this is often much easier to read than using functions to take apart values
added an explicit type signature for documentation purposes
here's what I think you meant:
fraclist :: (Integral t1) => [(t, t1, t1)] -> [(t, t1, t1, t1)]
fraclist xs = [(x, y, z, div y z) | (x, y, z) <- xs]
I'll leave the sorting to you.
I think you want just
fraclist xs = [(y,r,q, r `quot` q) | (y,r,q) <- xs]
(Note: I used quot instead of (/) since you named the components int1, int2.)
A variant not using list comprehensions is
fraclist = map (\(y,r,q) -> (y,r,q, r `quot` q))
Your code doesn't compile, in such cases it is better to post the error message so people can see at one glance what the probable cause is.
You get a parse erro on the first <- in
fraclist x = [ (y,r,q,z) : y <- first (head x) | r <- scnd (head x) | q <- last (head x) | z <- r/q ] : fraclist tail x
because the expression (y,r,q,z) : y <- first (head x) before the first | separating the generated expressions from the generator expressions isn't well-formed. I think it's just a typo and you meant to use | instead of (:) there too.
Then you have several | separators in your list comprehension, which is not valid without the ParallelListComp extension. However, the code doesn't look like a parallel list comprehension is really what you attempt here, since all three values are drawn from the same list. Finally, the last part | z <- r/q is again not well-formed, since r/q is not a list from which elements can be drawn in a list comprehension. You probably intended let z = r/q there.
Here is a simple solution without list comprehension:
import Data.List
-- (string, int1, int2) -> (string int1, int2, (int1/int2))
fraclist list = map generateTuple list
where generateTuple (label, value, weight) = (label, value, weight, (value)/(weight))
sortFracListByValueWeightRatio list = sortBy sorter list
where sorter (_,_,_,d) (_,_,_,h) = if d > h then GT else LT
testList = [("first",3.0,4.0), ("second",4.0,7.0)]
Nothing fancy (I've only used haskell a week).
fraclist works by mapping the generateTuple function to the list. The generateTuple function simply returns a tuple of form (title, value, weight, value/weight). Map is a built in function which simply applies a given function to each element of the list.
The sortFracListByValueWeightRatio (sorry for the long name) uses the built in sortBy function (comes from Data.List), which sorts a given list using a custom function for comparing items. Sorter is my item comparer, and it simply compares the value/weight ratios and returns either GT or LT (Greater Than / Lower Than). Hence, the list items are compared using the custom comparer, and sorted based on its answer.
A significant improvement of readability would probably be to use types to describe the values instead of just tuples. Also I'm using doubles in the test list, but that is easy to change.