Difference between revisions of "99 questions/1 to 10"
Basvandijk (talk | contribs) |
m |
||
(57 intermediate revisions by 30 users not shown) | |||
Line 1: | Line 1: | ||
__NOTOC__ |
__NOTOC__ |
||
− | + | This is part of [[H-99:_Ninety-Nine_Haskell_Problems|Ninety-Nine Haskell Problems]], based on [https://sites.google.com/site/prologsite/prolog-problems Ninety-Nine Prolog Problems] and [http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html 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 == |
== Problem 1 == |
||
+ | <div style="border-bottom:1px solid #eee">(*) Find the last element of a list. <span style="float:right"><small>[[99 questions/Solutions/1|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
− | ( |
+ | (Note that the Lisp transcription of this problem is incorrect.) |
− | |||
− | Example: |
||
− | |||
− | <pre> |
||
− | * (my-last '(a b c d)) |
||
− | (D) |
||
− | </pre> |
||
Example in Haskell: |
Example in Haskell: |
||
<haskell> |
<haskell> |
||
− | + | λ> myLast [1,2,3,4] |
|
4 |
4 |
||
− | + | λ> myLast ['x','y','z'] |
|
'z' |
'z' |
||
</haskell> |
</haskell> |
||
− | Solution: |
||
− | |||
− | <haskell> |
||
− | last :: [a] -> a |
||
− | last [x] = x |
||
− | last (_:xs) = last xs |
||
− | </haskell> |
||
− | |||
− | This function is defined in Prelude. |
||
== Problem 2 == |
== Problem 2 == |
||
+ | <div style="border-bottom:1px solid #eee">(*) Find the last-but-one (or second-last) element of a list. <span style="float:right"><small>[[99 questions/Solutions/2|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
− | ( |
+ | (Note that the Lisp transcription of this problem is incorrect.) |
− | <pre> |
||
− | Example: |
||
− | * (my-but-last '(a b c d)) |
||
− | (C D) |
||
− | </pre> |
||
+ | Example in Haskell: |
||
− | This can be done by dropping all but the last two elements of a list: |
||
<haskell> |
<haskell> |
||
− | myButLast |
+ | λ> myButLast [1,2,3,4] |
+ | 3 |
||
− | myButLast list = drop ((length list) - 2) list |
||
+ | λ> myButLast ['a'..'z'] |
||
+ | 'y' |
||
</haskell> |
</haskell> |
||
+ | |||
== Problem 3 == |
== Problem 3 == |
||
+ | <div style="border-bottom:1px solid #eee">(*) Find the K'th element of a list. <span style="float:right"><small>[[99 questions/Solutions/3|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
− | (*) Find the K'th element of a list. |
||
The first element in the list is number 1. |
The first element in the list is number 1. |
||
− | <pre> |
||
Example: |
Example: |
||
+ | |||
+ | <pre> |
||
* (element-at '(a b c d e) 3) |
* (element-at '(a b c d e) 3) |
||
+ | c |
||
− | C |
||
</pre> |
</pre> |
||
+ | Example in Haskell: |
||
− | This is (almost) the infix operator !! in Prelude, which is defined as: |
||
<haskell> |
<haskell> |
||
+ | λ> elementAt [1,2,3] 2 |
||
− | (!!) :: [a] -> Int -> a |
||
+ | 2 |
||
− | (x:_) !! 0 = x |
||
+ | λ> elementAt "haskell" 5 |
||
− | (_:xs) !! n = xs !! (n-1) |
||
+ | 'e' |
||
</haskell> |
</haskell> |
||
− | Except this doesn't quite work, because !! is zero-indexed, and element-at should be one-indexed. So: |
||
− | |||
− | <haskell> |
||
− | elementAt :: [a] -> Int -> a |
||
− | elementAt list i = list !! (i-1) |
||
− | </haskell> |
||
== Problem 4 == |
== Problem 4 == |
||
+ | <div style="border-bottom:1px solid #eee">(*) Find the number of elements in a list. <span style="float:right"><small>[[99 questions/Solutions/4|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
+ | Example in Haskell: |
||
− | (*) Find the number of elements of a list. |
||
− | |||
− | This is "length" in Prelude, which is defined as: |
||
<haskell> |
<haskell> |
||
+ | λ> myLength [123, 456, 789] |
||
− | length :: [a] -> Int |
||
+ | 3 |
||
− | length [] = 0 |
||
+ | λ> myLength "Hello, world!" |
||
− | length (_:l) = 1 + length l |
||
+ | 13 |
||
</haskell> |
</haskell> |
||
+ | |||
== Problem 5 == |
== Problem 5 == |
||
+ | <div style="border-bottom:1px solid #eee">(*) Reverse a list. <span style="float:right"><small>[[99 questions/Solutions/5|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
+ | Example in Haskell: |
||
− | (*) Reverse a list. |
||
− | |||
− | This is "reverse" in Prelude, which is defined as: |
||
<haskell> |
<haskell> |
||
+ | λ> myReverse "A man, a plan, a canal, panama!" |
||
− | reverse :: [a] -> [a] |
||
+ | "!amanap ,lanac a ,nalp a ,nam A" |
||
− | reverse = foldl (flip (:)) [] |
||
+ | λ> myReverse [1,2,3,4] |
||
+ | [4,3,2,1] |
||
</haskell> |
</haskell> |
||
− | The standard definition is concise, but not very readable. Another way to define reverse is: |
||
− | |||
− | <haskell> |
||
− | reverse :: [a] -> [a] |
||
− | reverse [] = [] |
||
− | reverse (x:xs) = reverse xs ++ [x] |
||
− | </haskell> |
||
== Problem 6 == |
== Problem 6 == |
||
+ | <div style="border-bottom:1px solid #eee">(*) Find out whether a list is a palindrome. <span style="float:right"><small>[[99 questions/Solutions/6|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
− | + | Hint: A palindrome can be read forward or backward; e.g. (x a m a x). |
|
+ | Example in Haskell: |
||
− | This is trivial, because we can use reverse: |
||
<haskell> |
<haskell> |
||
− | isPalindrome |
+ | λ> isPalindrome [1,2,3] |
+ | False |
||
− | isPalindrome xs = xs == (reverse xs) |
||
+ | λ> isPalindrome "madamimadam" |
||
+ | True |
||
+ | λ> isPalindrome [1,2,4,8,16,8,4,2,1] |
||
+ | True |
||
</haskell> |
</haskell> |
||
+ | |||
== Problem 7 == |
== Problem 7 == |
||
+ | <div style="border-bottom:1px solid #eee">(**) Flatten a nested list structure. <span style="float:right"><small>[[99 questions/Solutions/7|Solutions]]</small></span> |
||
− | |||
+ | </div> |
||
− | (**) Flatten a nested list structure. |
||
+ | <br> |
||
Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively). |
Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively). |
||
+ | |||
+ | Example: |
||
<pre> |
<pre> |
||
− | Example: |
||
* (my-flatten '(a (b (c d) e))) |
* (my-flatten '(a (b (c d) e))) |
||
(A B C D E) |
(A B C D E) |
||
</pre> |
</pre> |
||
+ | Example in Haskell: |
||
− | This is tricky, because lists in Haskell are homogeneous. [1, [2, [3, 4], 5]] |
||
− | is a type error. We have to devise some way of represent a list that may (or |
||
− | may not) be nested: |
||
+ | We have to define a new data type, because lists in Haskell are homogeneous. |
||
<haskell> |
<haskell> |
||
− | data NestedList a = Elem a | List [NestedList a] |
+ | data NestedList a = Elem a | List [NestedList a] |
− | |||
− | flatten :: NestedList a -> [a] |
||
− | flatten (Elem x) = [x] |
||
− | flatten (List []) = [] |
||
− | flatten (List (x:xs)) = flatten x ++ flatten (List xs) |
||
</haskell> |
</haskell> |
||
+ | <haskell> |
||
− | Our NestedList datatype is either a single element of some type (Elem a), or a |
||
+ | λ> flatten (Elem 5) |
||
− | list of NestedLists of the same type. (List [NestedList a]). Let's try it out in ghci: |
||
− | |||
− | <pre> |
||
− | *Main> flatten (Elem 5) |
||
[5] |
[5] |
||
− | + | λ> flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]]) |
|
[1,2,3,4,5] |
[1,2,3,4,5] |
||
− | + | λ> flatten (List []) |
|
[] |
[] |
||
− | </ |
+ | </haskell> |
+ | |||
== Problem 8 == |
== Problem 8 == |
||
+ | <div style="border-bottom:1px solid #eee">(**) Eliminate consecutive duplicates of list elements. <span style="float:right"><small>[[99 questions/Solutions/8|Solutions]]</small></span> |
||
− | |||
+ | </div> |
||
− | (**) Eliminate consecutive duplicates of list elements. |
||
+ | <br> |
||
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: |
||
− | *Main> compress ['a','a','a','a','b','c','c','a','a','d','e','e','e','e'] |
||
− | ['a','b','c','a','d','e'] |
||
− | </pre> |
||
− | Solution: |
||
<haskell> |
<haskell> |
||
+ | λ> compress "aaaabccaadeeee" |
||
− | compress :: Eq a => [a] -> [a] |
||
+ | "abcade" |
||
− | compress = map head . group |
||
</haskell> |
</haskell> |
||
− | 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: |
||
− | |||
− | <haskell>compress xs = map head $ group xs</haskell> |
||
== Problem 9 == |
== Problem 9 == |
||
+ | <div style="border-bottom:1px solid #eee">(**) Pack consecutive duplicates of list elements into sublists. <span style="float:right"><small>[[99 questions/Solutions/9|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
− | (**) 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: |
||
− | </pre> |
||
− | Solution: |
||
<haskell> |
<haskell> |
||
+ | λ> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', |
||
− | group (x:xs) = let (first,rest) = span (==x) xs |
||
− | + | 'a', 'd', 'e', 'e', 'e', 'e'] |
|
+ | ["aaaa","b","cc","aa","d","eeee"] |
||
− | group [] = [] |
||
</haskell> |
</haskell> |
||
+ | |||
− | 'group' is also in the Prelude, here's an implementation using 'span'. |
||
− | |||
== Problem 10 == |
== Problem 10 == |
||
+ | <div style="border-bottom:1px solid #eee">(*) Run-length encoding of a list. <span style="float:right"><small>[[99 questions/Solutions/10|Solutions]]</small></span> |
||
+ | </div> |
||
+ | <br> |
||
+ | Use the result of Problem 9 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. |
||
− | (*) 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: |
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> |
||
− | |||
− | Example: |
||
− | <example in lisp> |
||
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')] |
||
+ | </haskell> |
||
− | </pre> |
||
− | Solution: |
||
− | <haskell> |
||
− | encode xs = map (\x -> (length x,head x)) (group xs) |
||
− | </haskell> |
||
− | |||
[[Category:Tutorials]] |
[[Category:Tutorials]] |
Latest revision as of 05:27, 10 June 2023
This is part of Ninety-Nine Haskell Problems, based on Ninety-Nine Prolog Problems and Ninety-Nine Lisp Problems.
Problem 1
(Note that the Lisp transcription of this problem is incorrect.)
Example in Haskell:
λ> myLast [1,2,3,4]
4
λ> myLast ['x','y','z']
'z'
Problem 2
(Note that the Lisp transcription of this problem is incorrect.)
Example in Haskell:
λ> myButLast [1,2,3,4]
3
λ> myButLast ['a'..'z']
'y'
Problem 3
The first element in the list is number 1. Example:
* (element-at '(a b c d e) 3) c
Example in Haskell:
λ> elementAt [1,2,3] 2
2
λ> elementAt "haskell" 5
'e'
Problem 4
Example in Haskell:
λ> myLength [123, 456, 789]
3
λ> myLength "Hello, world!"
13
Problem 5
Example in Haskell:
λ> myReverse "A man, a plan, a canal, panama!"
"!amanap ,lanac a ,nalp a ,nam A"
λ> myReverse [1,2,3,4]
[4,3,2,1]
Problem 6
Hint: A palindrome can be read forward or backward; e.g. (x a m a x).
Example in Haskell:
λ> isPalindrome [1,2,3]
False
λ> isPalindrome "madamimadam"
True
λ> isPalindrome [1,2,4,8,16,8,4,2,1]
True
Problem 7
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:
We have to define a new data type, because lists in Haskell are homogeneous.
data NestedList a = Elem a | List [NestedList a]
λ> flatten (Elem 5)
[5]
λ> flatten (List [Elem 1, List [Elem 2, List [Elem 3, Elem 4], Elem 5]])
[1,2,3,4,5]
λ> flatten (List [])
[]
Problem 8
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:
λ> compress "aaaabccaadeeee"
"abcade"
Problem 9
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:
λ> pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a',
'a', 'd', 'e', 'e', 'e', 'e']
["aaaa","b","cc","aa","d","eeee"]
Problem 10
Use the result of Problem 9 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')]