# Difference between revisions of "H-99: Ninety-Nine Haskell Problems"

m (formatting change) |
|||

Line 3: | Line 3: | ||

== Problem 1 == |
== Problem 1 == |
||

⚫ | |||

(*) Find the last box of a list. |
(*) Find the last box of a list. |
||

⚫ | |||

Example: |
Example: |
||

* (my-last '(a b c d)) |
* (my-last '(a b c d)) |
||

Line 20: | Line 20: | ||

== Problem 2 == |
== Problem 2 == |
||

⚫ | |||

<pre> |
<pre> |
||

⚫ | |||

Example: |
Example: |
||

* (my-but-last '(a b c d)) |
* (my-but-last '(a b c d)) |
||

Line 36: | Line 36: | ||

== Problem 3 == |
== Problem 3 == |
||

− | <pre> |
||

(*) Find the K'th element of a list. |
(*) 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: |
||

* (element-at '(a b c d e) 3) |
* (element-at '(a b c d e) 3) |
||

Line 61: | Line 61: | ||

== Problem 4 == |
== Problem 4 == |
||

− | <pre> |
||

(*) Find the number of elements of a list. |
(*) Find the number of elements of a list. |
||

− | </pre> |
||

This is "length" in Prelude, which is defined as: |
This is "length" in Prelude, which is defined as: |
||

Line 75: | Line 73: | ||

== Problem 5 == |
== Problem 5 == |
||

− | <pre> |
||

(*) Reverse a list. |
(*) Reverse a list. |
||

− | </pre> |
||

This is "reverse" in Prelude, which is defined as: |
This is "reverse" in Prelude, which is defined as: |
||

Line 96: | Line 92: | ||

== Problem 6 == |
== Problem 6 == |
||

− | <pre> |
||

⚫ | |||

− | (*) Find out whether a list is a palindrome. |
||

⚫ | |||

− | </pre> |
||

This is trivial, because we can use reverse: |
This is trivial, because we can use reverse: |
||

Line 110: | Line 103: | ||

== Problem 7 == |
== Problem 7 == |
||

− | <pre> |
||

(**) Flatten a nested list structure. |
(**) 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). |
Transform a list, possibly holding lists as elements into a `flat' list by replacing each list with its elements (recursively). |
||

+ | <pre> |
||

Example: |
Example: |
||

* (my-flatten '(a (b (c d) e))) |
* (my-flatten '(a (b (c d) e))) |
||

Line 145: | Line 139: | ||

== Problem 8 == |
== Problem 8 == |
||

− | <pre> |
||

+ | |||

(**) Eliminate consecutive duplicates of list elements. |
(**) Eliminate consecutive duplicates of list elements. |
||

⚫ | |||

⚫ | |||

+ | |||

+ | <pre> |
||

Example: |
Example: |
||

* (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)) |

## Revision as of 05:54, 12 December 2006

These are Haskell translations of Ninety Nine Lisp Problems.

## Contents

## Problem 1

(*) Find the last box of a list.

Example: * (my-last '(a b c d)) (D)

This is "last" in Prelude, which is defined as:

```
last :: [a] -> a
last [x] = x
last (_:xs) = last xs
```

## Problem 2

(*) Find the last but one box of a list.

Example: * (my-but-last '(a b c d)) (C D)

This can be done by dropping all but the last two elements of a list:

```
myButLast :: [a] -> [a]
myButLast list = drop ((length list) - 2) list
```

## 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

This is (almost) the infix operator !! in Prelude, which is defined as:

```
(!!) :: [a] -> Int -> a
(x:_) !! 0 = x
(_:xs) !! n = xs !! (n-1)
```

Except this doesn't quite work, because !! is zero-indexed, and element-at should be one-indexed. So:

```
elementAt :: [a] -> Int -> a
elementAt list i = list !! (i-1)
```

## Problem 4

(*) Find the number of elements of a list.

This is "length" in Prelude, which is defined as:

```
length :: [a] -> Int
length [] = 0
length (_:l) = 1 + length l
```

## Problem 5

(*) Reverse a list.

This is "reverse" in Prelude, which is defined as:

```
reverse :: [a] -> [a]
reverse = foldl (flip (:)) []
```

The standard definition is concise, but not very readable. Another way to define reverse is:

```
reverse :: [a] -> [a]
reverse [] = []
reverse (x:xs) = reverse xs ++ [x]
```

## 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).

This is trivial, because we can use reverse:

```
isPalindrome :: (Eq a) => [a] -> Bool
isPalindrome xs = xs == (reverse xs)
```

## 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)

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:

```
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)
```

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]). Let's try it out in ghci:

*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']

Solution:

```
compress = map head . group
```

We simply group equal values together (group), then take the head of each.