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


Expanding on Hello, world

Anyone even moderately familiar with my other tutorials will recognize the pattern of starting with a simple hello world program and then expanding upon it.

So, let's create a function "greet" which takes a name and greets that person.

Our Main.hs looked like:

module Main where

main = putStrLn "Hello, world!"

Now we're going to expand it with:

module Main where

main = greet "Bob"

greet name = putStrLn ("Hello, " ++ name ++ "!")

Of course, what if we want just the greeting string?

module Main where

main = greet "Bob"

greet name = putStrLn (greeting name)

greeting name = "Hello, " ++ name ++ "!"

Tidying the code up - Haskell tricks

Haskell by default infers the types of data being used in a program, but for documentation purposes, we can explicitly specify the types a function uses and returns.

Doing this, we write a type signature for main. The "main" function does an IO action, and returns the closest thing you can get in Haskell to nothing, so:

module Main where

main :: IO ()
main = greet "Bob"

greet name = putStrLn (greeting name)

greeting name = "Hello, " ++ name ++ "!"

Double colons separate the name of a function and its signature.

Continuing, we generate a signature for the "greet" and "greeting" functions.

module Main where

main :: IO ()
main = greet "Bob"

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

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

These signatures are saying, "greet takes a string as an argument and does an IO operation," and, "greeting takes a string as an argument and returns another string."

greet name = putStrLn (greeting name)

Here we use parentheses because otherwise this would be seen as putStrLn taking two arguments, "greeting" and "name". Since putStrLn only takes one argument, this would clearly be erroneous.

But the parentheses can get annoying, so we have the $ operator. Essentially, the $ operator takes the value on its right hand side and gives it to the function on the left hand side. So, now our greet function looks like:

greet name = putStrLn $ greeting name

So, our code now looks like:

module Main where

main :: IO ()
main = greet "Bob"

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

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

Input as well as output

All of this greeting isn't very much good unless we can get input from the user as well, to find out their name.

IO actions aren't quite like other functions. To "chain" them together in sequence we use the keyword "do".

module Main where

main :: IO ()
main = do putStr "You are? "
          name <- getLine
          greet name

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

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

Probably the most immediately notiecable change is the use of indentation. Haskell uses what's referred to as "layout", so semi-colons and braces aren't necessary. They are available:

main = do { putStr "You are? ";
name <- getLine;
greet name }

Of course, the "layout" approach is so much nicer that it'd be silly to use braces and semi-colons.

The second new bit of syntax is:

name <- getLine

The return of getLine is a string, but an IO "tainted" string, which can't be immediately used. Using the <- syntax, "name" is a plain old string we can use elsewhere.

Conditionals

How about when the name given to the greeting function is "Haskell", the greeting is "Hey, whadda ya know? This is a Haskell program!"

module Main where

main :: IO ()
main = do putStr "You are? "
          name <- getLine
          greet name

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

greeting :: String -> String
greeting name =
  if name == "Haskell"
    then "Hey, whadda ya know?  This is a Haskell program!"
    else "Hello, " ++ name ++ "!"

This should look fairly straightforward to a programmer with basic experience in other languages. Also, again we use "layout" to signify the structure of the conditional.

Case expressions

Let's say we want our program to greet "Matz" with, "You make a good language." Using only "if":

module Main where

main :: IO ()
main = do putStr "You are? "
          name <- getLine
          greet name

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

greeting :: String -> String
greeting name =
  if name == "Haskell"
    then "Hey, whadda ya know?  This is a Haskell program!"
    else if name == "Matz"
           then "You make a good language."
           else "Hello, " ++ name ++ "!"

Wow, that's ugly. Fortunately, we have the case expression that should look familiar to programmers.

module Main where

main :: IO ()
main = do putStr "You are? "
          name <- getLine
          greet name

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

greeting :: String -> String
greeting name =
  case name of
    "Haskell" -> "Hey, whadda ya know?  This is a Haskell program!"
    "Matz"    -> "You make a good language."
    otherwise -> "Hello, " ++ name ++ "!"

As with "if", we use layout.

Overloading functions

Of course, we can do this even more cleanly by overloading the greeting function.

module Main where

main :: IO ()
main = do putStr "You are? "
          name <- getLine
          greet name

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 ++ "!"






Next Page
spacer
30762 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