Haskell/Solutions/Higher-order functions and Currying

← Back to Higher-order functions and Currying

quickSort, Take TwoEdit

Write insensitive, such that quickSort insensitive dictionary gives ["a", "for", "have", "I", "Linux", "thing"]
import Data.Char (toUpper)
insensitive string1 string2 = compare (map toUpper string1) (map toUpper string2)

Instead of comparing the two strings directly, we compare the all uppercase version. The order of the original two strings is then based on the order of the uppercase versions.

Higher-Order Functions and TypesEdit

The following exercise combines what you have learned about higher order functions, recursion and IO. We are going to recreate what programmers from more popular languages call a "for loop". Implement a function
for :: a -> (a->Bool) -> (a->a) -> (a-> IO ()) -> IO ()
for i p f job = -- ???
An example of how this function would be used might be
for 1 (<10) (+1) (\x -> print x)
which prints the numbers 1 to 10 on the screen.

Starting from an initial value i, the for executes job i. It then modifies this value f i and checks to see if the modified value satisfies some condition. If it does, it stops; otherwise, the for loop continues, using the modified f i in place of i.

  1. The paragraph above gives an imperative description of the for loop. What would a more functional description be?
  2. Implement the for loop in Haskell.
  3. Why does Haskell not have a for loop as part of the language, or in the standard library?

Some more challenging exercises you could try

  1. What would be a more Haskell-like way of performing a task like 'print the list of numbers from 1 to 10'? Are there any problems with your solution?
  2. Implement a function sequenceIO :: [IO a] -> IO [a]. Given a list of actions, this function runs each of the actions in order and returns all their results as a list.
  3. Implement a function mapIO :: (a -> IO b) -> [a] -> IO [b] which given a function of type a -> IO b and a list of type [a], runs that action on each item in the list, and returns the results.

Part 1:

2. A for loop in Haskell:

for :: a -> (a->Bool) -> (a->a) -> (a->IO()) -> IO()
for i p f job =
    if p i
    then do
      job i
      for (f i) p f job
    else return ()

*Main> for 0 (<3) (+1) (print)

Part 2:


sequenceIO :: [IO a] -> IO [a]
sequenceIO [] = return []
sequenceIO (a:as) = do {v <-a ; vs <- (sequenceIO as) ; return (v : vs)}

In this function, the `vs <- (sequenceIO as)' section recursively calls sequenceIO to generate the rest of the passed list, using `<-' extract the values of each returned IO object, and then finally returns the IO object with `v' Consed onto the generated list, `vs'.


mapIO :: (a -> IO b) -> [a] -> IO [b]
mapIO f [] = return []
mapIO f (x:xs) = do {y <- (f x) ; ys <- (mapIO f xs) ; return (y : ys)}   
Last modified on 7 May 2012, at 06:13