Difference between revisions of "99 questions/1 to 10"
(fixed broken links to solutions) |
(moved solutions 6-10 to new subpages of 99 questions/Solutions, and cleaned up formatting) |
||
Line 49: | Line 49: | ||
<pre> |
<pre> |
||
* (element-at '(a b c d e) 3) |
* (element-at '(a b c d e) 3) |
||
+ | c |
||
− | C |
||
</pre> |
</pre> |
||
Line 111: | Line 111: | ||
</haskell> |
</haskell> |
||
+ | [[99 questions/Solutions/6 | Solutions]] |
||
− | Solution: |
||
− | <haskell> |
||
− | isPalindrome :: (Eq a) => [a] -> Bool |
||
− | isPalindrome xs = xs == (reverse xs) |
||
− | </haskell> |
||
== Problem 7 == |
== Problem 7 == |
||
Line 142: | Line 138: | ||
</haskell> |
</haskell> |
||
+ | [[99 questions/Solutions/7 | Solutions]] |
||
− | Solution: |
||
− | <haskell> |
||
− | data NestedList a = Elem a | List [NestedList a] |
||
− | |||
− | flatten :: NestedList a -> [a] |
||
− | flatten (Elem x) = [x] |
||
− | flatten (List x) = concatMap flatten x |
||
− | </haskell> |
||
− | |||
− | We have to define a new data type, because lists in Haskell are homogeneous. |
||
− | [1, [2, [3, 4], 5]] is a type error. Therefore, we must have a way of |
||
− | representing a list that may (or may not) be nested. |
||
− | |||
− | Our NestedList datatype is either a single element of some type (Elem a), or a |
||
− | list of NestedLists of the same type. (List [NestedList a]). |
||
== Problem 8 == |
== Problem 8 == |
||
Line 165: | Line 147: | ||
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed. |
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed. |
||
− | <pre> |
||
Example: |
Example: |
||
+ | |||
+ | <pre> |
||
* (compress '(a a a a b c c a a d e e e e)) |
* (compress '(a a a a b c c a a d e e e e)) |
||
(A B C A D E) |
(A B C A D E) |
||
+ | </pre> |
||
Example in Haskell: |
Example in Haskell: |
||
+ | |||
+ | <haskell> |
||
*Main> compress ['a','a','a','a','b','c','c','a','a','d','e','e','e','e'] |
*Main> compress ['a','a','a','a','b','c','c','a','a','d','e','e','e','e'] |
||
['a','b','c','a','d','e'] |
['a','b','c','a','d','e'] |
||
− | </pre> |
||
− | |||
− | Solution: |
||
− | <haskell> |
||
− | compress :: Eq a => [a] -> [a] |
||
− | compress = map head . group |
||
</haskell> |
</haskell> |
||
+ | [[99 questions/Solutions/8 | Solutions]] |
||
− | We simply group equal values together (group), then take the head of each. |
||
− | Note that (with GHC) we must give an explicit type to ''compress'' otherwise we get: |
||
− | <haskell> |
||
− | Ambiguous type variable `a' in the constraint: |
||
− | `Eq a' |
||
− | arising from use of `group' |
||
− | Possible cause: the monomorphism restriction applied to the following: |
||
− | compress :: [a] -> [a] |
||
− | Probable fix: give these definition(s) an explicit type signature |
||
− | or use -fno-monomorphism-restriction |
||
− | </haskell> |
||
− | |||
− | We can circumvent the monomorphism restriction by writing ''compress'' this way (See: section 4.5.4 of [http://haskell.org/onlinereport the report]): |
||
− | |||
− | <haskell>compress xs = map head $ group xs</haskell> |
||
− | |||
− | An alternative solution is |
||
− | |||
− | <haskell> |
||
− | compress [] = [] |
||
− | compress [a] = [a] |
||
− | compress (x : y : xs) = (if x == y then [] else [x]) ++ compress (y : xs) |
||
− | </haskell> |
||
== Problem 9 == |
== Problem 9 == |
||
Line 210: | Line 168: | ||
(**) Pack consecutive duplicates of list elements into sublists. |
(**) Pack consecutive duplicates of list elements into sublists. |
||
If a list contains repeated elements they should be placed in separate sublists. |
If a list contains repeated elements they should be placed in separate sublists. |
||
+ | |||
+ | Example: |
||
<pre> |
<pre> |
||
− | Example: |
||
* (pack '(a a a a b c c a a d e e e e)) |
* (pack '(a a a a b c c a a d e e e e)) |
||
((A A A A) (B) (C C) (A A) (D) (E E E E)) |
((A A A A) (B) (C C) (A A) (D) (E E E E)) |
||
+ | </pre> |
||
− | <example in lisp> |
||
Example in Haskell: |
Example in Haskell: |
||
+ | |||
+ | <haskell> |
||
*Main> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e'] |
*Main> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e'] |
||
["aaaa","b","cc","aa","d","eeee"] |
["aaaa","b","cc","aa","d","eeee"] |
||
− | </pre> |
||
− | |||
− | Solution: |
||
− | <haskell> |
||
− | pack (x:xs) = let (first,rest) = span (==x) xs |
||
− | in (x:first) : pack rest |
||
− | pack [] = [] |
||
</haskell> |
</haskell> |
||
+ | [[99 questions/Solutions/9 | Solutions]] |
||
− | A more verbose solution is |
||
− | <haskell> |
||
− | pack :: Eq a => [a] -> [[a]] |
||
− | 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 |
||
− | </haskell> |
||
− | This is implemented as <hask>group</hask> in <hask>Data.List</hask>. |
||
== Problem 10 == |
== Problem 10 == |
||
Line 251: | Line 193: | ||
Example: |
Example: |
||
<pre> |
<pre> |
||
− | + | * (encode '(a a a a b c c a a d e e e e)) |
|
− | + | ((4 A) (1 B) (2 C) (2 A) (1 D)(4 E)) |
|
</pre> |
</pre> |
||
Example in Haskell: |
Example in Haskell: |
||
− | < |
+ | <haskell> |
encode "aaaabccaadeeee" |
encode "aaaabccaadeeee" |
||
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')] |
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')] |
||
− | </pre> |
||
− | |||
− | Solution: |
||
− | <haskell> |
||
− | encode xs = map (\x -> (length x,head x)) (group xs) |
||
</haskell> |
</haskell> |
||
+ | [[99 questions/Solutions/10 | Solutions]] |
||
− | which can also be expressed as a list comprehension: |
||
− | <haskell> |
||
− | [(length x, head x) | x <- group xs] |
||
− | </haskell> |
||
− | Or writing it [[Pointfree]]: |
||
− | |||
− | <haskell> |
||
− | encode :: Eq a => [a] -> [(Int, a)] |
||
− | encode = map (\x -> (length x, head x)) . group |
||
− | </haskell> |
||
− | |||
− | Or (ab)using the "&&&" arrow operator for tuples: |
||
− | |||
− | <haskell> |
||
− | encode :: Eq a => [a] -> [(Int, a)] |
||
− | encode xs = map (length &&& head) $ group xs |
||
− | </haskell> |
||
[[Category:Tutorials]] |
[[Category:Tutorials]] |
Revision as of 15:27, 13 July 2010
This is part of Ninety-Nine Haskell Problems, based on Ninety-Nine Prolog Problems and Ninety-Nine Lisp Problems.
If you want to work on one of these, put your name in the block so we know someone's working on it. Then, change n in your block to the appropriate problem number, and fill in the <Problem description>,<example in lisp>,<example in Haskell>,<solution in haskell> and <description of implementation> fields.
Problem 1
(*) Find the last element of a list.
(Note that the Lisp transcription of this problem is incorrect.)
Example in Haskell:
Prelude> myLast [1,2,3,4]
4
Prelude> myLast ['x','y','z']
'z'
Problem 2
(*) Find the last but one element of a list.
(Note that the Lisp transcription of this problem is incorrect.)
Example in Haskell:
Prelude> myButLast [1,2,3,4]
3
Prelude> myButLast ['a'..'z']
'y'
Problem 3
(*) Find the K'th element of a list. The first element in the list is number 1.
Example:
* (element-at '(a b c d e) 3) c
Example in Haskell:
Prelude> elementAt [1,2,3] 2
2
Prelude> elementAt "haskell" 5
'e'
Problem 4
(*) Find the number of elements of a list.
Example in Haskell:
Prelude> myLength [123, 456, 789]
3
Prelude> myLength "Hello, world!"
13
Problem 5
(*) Reverse a list.
Example in Haskell:
Prelude> reverse "A man, a plan, a canal, panama!"
"!amanap ,lanac a ,nalp a ,nam A"
Prelude> reverse [1,2,3,4]
[4,3,2,1]
Problem 6
(*) Find out whether a list is a palindrome. A palindrome can be read forward or backward; e.g. (x a m a x).
Example in Haskell:
*Main> isPalindrome [1,2,3]
False
*Main> isPalindrome "madamimadam"
True
*Main> isPalindrome [1,2,4,8,16,8,4,2,1]
True
Problem 7
(**) Flatten a nested list structure.
Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively).
Example:
* (my-flatten '(a (b (c d) e))) (A B C D E)
Example in Haskell:
*Main> flatten (Elem 5)
[5]
*Main> flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])
[1,2,3,4,5]
*Main> flatten (List [])
[]
Problem 8
(**) Eliminate consecutive duplicates of list elements.
If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.
Example:
* (compress '(a a a a b c c a a d e e e e)) (A B C A D E)
Example in Haskell:
*Main> compress ['a','a','a','a','b','c','c','a','a','d','e','e','e','e']
['a','b','c','a','d','e']
Problem 9
(**) Pack consecutive duplicates of list elements into sublists. If a list contains repeated elements they should be placed in separate sublists.
Example:
* (pack '(a a a a b c c a a d e e e e)) ((A A A A) (B) (C C) (A A) (D) (E E E E))
Example in Haskell:
*Main> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e']
["aaaa","b","cc","aa","d","eeee"]
Problem 10
(*) Run-length encoding of a list. Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as lists (N E) where N is the number of duplicates of the element E.
Example:
* (encode '(a a a a b c c a a d e e e e)) ((4 A) (1 B) (2 C) (2 A) (1 D)(4 E))
Example in Haskell:
encode "aaaabccaadeeee"
[(4,'a'),(1,'b'),(2,'c'),(2,'a'),(1,'d'),(4,'e')]