Misc Links
Forum Archive
News Archive
File DB
 

Ads
 

Advertisement
 

Latest Forum Topics
wow 56 k modems are
Posted by Red Squirrel
on Oct 14 2013, 11:52:23 pm

I Need A Program
Posted by rovingcowboy
on Sep 23 2013, 5:37:59 pm

having trouble witn lan
Posted by rovingcowboy
on Sep 23 2013, 5:40:56 pm

new problem for me
Posted by rovingcowboy
on Sep 23 2013, 5:54:09 pm

RBC Royal Bank
Posted by Red Squirrel
on Aug 13 2013, 6:48:08 pm

 

Introduction to Haskell
Functional programming with Haskell
By Chris Dutton


Loops

At 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:

  • return ()

    What does "return" do? This basically turns () into IO (), which is the return our main function wants.

  • Why is "do" repeated in the "if" expression? The "if" basically interrupts the chain of expressions we were creating. To start another "chain" we need to use "do" again.

Lists

So, 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 down

As 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 function

Since 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 one

Not 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
spacer
30493 Hits Pages: [1] [2] [3] [4] [5] [6] 6 Comments
spacer


Latest comments (newest first)
Posted by genea on December 12th 2005 (13:14)
Very good article, with the part about type classes and the ability for a data type derived from a given class being able to automatically inherit the method (functions) from the class definition. I guess I missed that in the mountain of literature I had read and had been up till now missing the benefit of this info... I liked dobbing about with HASKELL and this just makes me believe, that it will have a bright future ahead, or one of the languages derived from it, such as CLEAN.
Thanks again.. and I too would like to see the next six!!
gene

spacer
Posted by wtd on June 06th 2005 (19:10)
QUOTE (HHH @ Jun 4 2005, 12:40 PM)
Hi,
how can I do a line skip in a String. I mean that one String ouput looks like this:

Hello, (line skip)
....

CODE
putStrLn "Hello"


The "Ln" means "line".

If you just want to skip a line...

CODE
putStrLn ""


Or you could make that a function.

CODE
skipLine = putStrLn ""

spacer
Posted by wtd on January 01th 2005 (16:44)
QUOTE (fred laforge @ Jan 11 2005, 10:03 AM)
great tutorial -- when will you post the next 6 lessons? :-)

Heh. That one took a bit out of me, so there might just be smaller updates for a while. smile.gif.

spacer
Posted by wtd on January 01th 2005 (02:12)
In my introduction to Haskell I createded a simple function greeting, which takes a name as a string and formulates a greeting.

CODE
greeting :: String -> String
greeting name = "Hello, " ++ name ++ "!"


And then, I created a greet function which takes a name and prints the greeting for it.

CODE
greet :: String -> IO ()
greet name = putStrLn (greeting name)


The latter function I rewrote as:

CODE
greet :: String -> IO ()
greet name = putStrLn $ greeting name


Now, the argument "name" should appear quite redundant in that last example. It is. What if, instead, we could simply combine the two functions, "greeting" and "putStrLn".

Haskell provides an easy mechanism for doing so.

CODE
greet :: String -> IO ()
greet = putStrLn . greeting


Now, we can make a similar observation about the greeting function.

CODE
greeting :: String -> String
greeting name = "Hello, " ++ name ++ "!"


This is really two functions, since operators are just functions. Given the order of evaluation, this could be rewritten:

CODE
greeting :: String -> String
greeting name = "Hello, " ++ (name ++ "!")


Now, since we can partially apply functions - give them one argument, and get back a function which takes another argument and gives us the rest - we can rewrite this as:

CODE
greeting :: String -> String
greeting = ("Hello, " ++) . (++ "!")


Just as in the original, the function takes a string, appends "!" to it, then prepends "Hello, " to that.

spacer
Posted by wtd on January 01th 2005 (19:54)
Oh, and when you get around to writing something in Haskell, and you have questions, feel free to ask. smile.gif
spacer
View all comments
Post comment


Top Articles Latest Articles
- What are .bin files for? (669062 reads)
- Text searching in linux with grep (161180 reads)
- Big Brother and Ndisuio.sys (150471 reads)
- PSP User's Guide (139547 reads)
- SPFDisk (Special Fdisk) Partition Manager (117240 reads)
- How to Use MDADM Linux Raid (188 reads)
- What is Cloud Computing? (1225 reads)
- Dynamic Forum Signatures (version 2) (8769 reads)
- Successfully Hacking your iPhone or iTouch (18714 reads)
- Ultima Online Newbie Guide (35906 reads)
corner image

This site best viewed in a W3C standard browser at 800*600 or higher
Site design by Red Squirrel | Contact
© Copyright 2019 Ryan Auclair/IceTeks, All rights reserved