|
|
Send spam to: website@xeonlive.com nick@xeonlive.com georgiapeach1241@aol.com Functional programming with Haskell By Chris Dutton LoopsAt this point you might be tempted to ask how Haskell handles looping, since that's a pretty basic thing for programmers to learn about in other languages. Haskell provides no special syntax for looping. All looping is achieved via recursion, where a function calls itself. module Main where main :: IO () main = do putStr "You are? " name <- getLine if name == "quit" then return () else do greet name main greet :: String -> IO () greet name = putStrLn $ greeting name greeting :: String -> String greeting "Haskell" = "Hey, whadda ya know? This is a Haskell program!" greeting "Matz" = "You make a good language." greeting name = "Hello, " ++ name ++ "!" A few questions that may come up from looking at this:
ListsSo, we can greet a number of people. Of course, what if we want to be able to get a list of people we've greeted? Well, we need a list. A list in Haskell can contain any number of values, as long as they're all the same type. The most basic list is an empty list: [] A small list of names might look like: ["Bob", "John"] Anything dealing with such structures in other programming languages, where we often use the term "array", should instantly bring to mind loops. Of course, we've already covered that. Haskell has no explicit looping syntax, but rather recursion. The solution, therefore is to find a way to define lists in a recursive manner. Thankfully, Haskell lists are naturally recursive. The : operator adds an element to the beginning of a list. Our name list could look like: "Bob" : "John" : [] Let's look at this in practice in a simple example. A simple range function should create a list of numbers from a start to an end. range s e = if s > e then [] else s : range (s + 1) e This could look fairly cryptic until we break a sample use of it down. range 1 5 1 : range 2 5 1 : 2 : range 3 5 1 : 2 : 3 : range 4 5 1 : 2 : 3 : 4 : range 5 5 1 : 2 : 3 : 4 : 5 : range 6 5 1 : 2 : 3 : 4 : 5 : [] 1 : 2 : 3 : 4 : [5] 1 : 2 : 3 : [4, 5] 1 : 2 : [3, 4, 5] 1 : [2, 3, 4, 5] [1, 2, 3, 4, 5] Seeing a function with two arguments points out an interesting fact about Haskell. Arguments to a function are simply separated by space, rather than commas, as in many other programming languages. So, we might as well jump right in. module Main where main :: IO [String] main = do putStr "You are? " name <- getLine if name == "quit" then return [] else do greet name nextRun <- main return $ name : nextRun greet :: String -> IO () greet name = putStrLn $ greeting name greeting :: String -> String greeting "Haskell" = "Hey, whadda ya know? This is a Haskell program!" greeting "Matz" = "You make a good language." greeting name = "Hello, " ++ name ++ "!" Breaking it downAs always, breaking a large complex program down into small, understandable components is essential to understanding. main :: IO [String] Our new signature for main indicates that it returns a list of strings. Of course it remains IO "tainted". return [] As before, if the user enters "quit", then we stop "looping". This time, though, we return an empty list, much as we did in the range function. nextRun <- main
We can't directly use main, since it returns an IO tainted list. Instead we first extract that list. return $ name : nextRun Here we add the current name onto the list of names generated by running the main function again, then "return" that list. It may seem odd, but the last run of the main function is the last to finish. Another functionSince this is getting fairly complex, perhaps we should break it into a separate function. module Main where main :: IO [String] main = greetMultiple greet :: String -> IO () greet name = putStrLn $ greeting name greeting :: String -> String greeting "Haskell" = "Hey, whadda ya know? This is a Haskell program!" greeting "Matz" = "You make a good language." greeting name = "Hello, " ++ name ++ "!" greetMultiple :: IO [String] greetMultiple = do putStr "You are? " name <- getLine if name == "quit" then return [] else do greet name nextRun <- greetMultiple return $ name : nextRun And another oneNot a lot has changed, but now we can do something with the list of strings greetMultiple returns. Let's introduce a new function to print all of the strings in a list. printAll :: [String] -> IO () printAll [] = return () printAll (x:xs) = do putStrLn x printAll xs Here we've overloaded the printAll function so printing an empty list just returns (). When I want to print an actual list, I use the pattern "(x:xs)". We've seen the : before. It's used when we're constructing lists. So here x is the first element in the list. The rest of the list is "xs", which can be read as the plural of "x". Our code now looks like: module Main where main :: IO () main = do names <- greetMultiple putStrLn "I greeted:" printAll names greet :: String -> IO () greet name = putStrLn $ greeting name greeting :: String -> String greeting "Haskell" = "Hey, whadda ya know? This is a Haskell program!" greeting "Matz" = "You make a good language." greeting name = "Hello, " ++ name ++ "!" greetMultiple :: IO [String] greetMultiple = do putStr "You are? " name <- getLine if name == "quit" then return [] else do greet name nextRun <- greetMultiple return $ name : nextRun printAll :: [String] -> IO () printAll [] = return () printAll (x:xs) = do putStrLn x printAll xs Next Page
|
![]() |
This site best viewed in a W3C standard browser at 800*600 or higher Site design by Red Squirrel | Contact © Copyright 2010 Ryan Auclair/IceTeks, All rights reserved |