Wednesday 27 May 2015

Echo the Command Line Arguments

ok another little toy: echo the command line arguments back to the terminal:-

module Main
    where

import System.Environment(getArgs)

main = do
  args <- getArgs
  mapM_ putStrLn args

This time we want the function getArgs from the library System.Environment

This has type

getArgs :: IO [String]

so naturally enough we get a list of strings back when the action is performed.

The IO action that writes to the string, function putStrLn, has the type:

putStrLn :: String -> IO ()

So this takes a string and gives you back the IO action that writes to the terminal but does not return any value.  We want to apply this to a list of strings and get an IO action that will write all of them to the terminal.  As before this is a job for mapM_, which has the type:

mapM_ :: Monad m => (a -> m b) -> [a] -> m ()

The (a -> m b) corresponds to our String -> IO ()  and the [a] bit to our [String]

I know I'm labouring this a bit but I want to get it clear in my head.  So let's call the resulting program echoargs:

>ghc main.hs -o echoargs.exe
Linking echoargs.exe ...

>echoargs curly larry moe
curly
larry
moe


Print Working Directory

How about a tiny program that does something useful: that is, tells me what directory I am currently in...

If you simplify your DOS prompt:

>prompt $G

then it doesn't show you but it does leave more space for typing.

Right.  The program looks like this:-

module Main
    where

import System.Directory(getCurrentDirectory)

main = do
  pwd <- getCurrentDirectory
  putStr pwd

This goes in a file main.hs and defines the main indeed only module with the entry point main.

To get access to the required system call we import the system library called System.Directory but specify (in the brackets) that the only reference we want to make is to the function getCurrentDirectory.

Now our main function consists of two IO actions that are stacked one on top of the other inside the do construct, which has the overall effect of taking the first action and then the second.

The first action calls the system function getCurrentDirectory and assigns the identifier pwd to the result.

The type of getSystemDirectory is

getCurrentDirectory :: IO FilePath

In other words it's an IO action that returns a value of type FilePath - and FilePath is just a synonym for the String type, so we can display this without further manipulation using a function that takes a string parameter.

So the second action prints the value of pwd to the terminal.

ok now to compile - compile the file main.hs and specify the output file to be called pwd.exe:

>dir
 Volume in drive C has no label.
 Volume Serial Number is 6496-80C4

 Directory of C:\Users\polly\Documents\Projects\Haskell\pwd

20/05/2015  21:17    <DIR>          .
20/05/2015  21:17    <DIR>          ..
20/05/2015  21:17               131 main.hs
20/05/2015  21:04               112 main.hs~
20/05/2015  21:16             1,389 notes.txt
20/05/2015  21:14             1,309 notes.txt~
               4 File(s)          2,941 bytes
               2 Dir(s)  273,825,931,264 bytes free

>ghc main.hs -o pwd.exe
[1 of 1] Compiling Main             ( main.hs, main.o )
Linking pwd.exe ...

Now I can run it and see my working directory:

>pwd
C:\Users\polly\Documents\Projects\Haskell\pwd
>

Question and Answer

The next quickie comes from Yet Another Haskell Tutorial by Hal Daume III

We write a string asking for the user's name, and then write back out a reply containing the name:-

module Main
    where

import System.IO

main = do
  hSetBuffering stdin LineBuffering
  putStrLn "Enter your name: "
  name <- getLine
  putStrLn ("Hello " ++ name ++ " have a scone")

But first... we apply the action hSetBuffering to the standard input with the option LineBuffering
so that the input does not wait to fill a block buffer before moving on but returns as soon as it has a line of input to work with.

The next action writes the string

Then we read a line from the terminal and assign name to the return value

Now we can concatenate a new reply together and write it out.

Now, when I did this import line:

import IO

I got this message from the compiler:

main.hs:4:8:
    Could not find module `IO'
    It is a member of the hidden package `haskell98-2.0.0.2'.
    Use -v to see a list of the files searched for.

But the compiler was happy when I changed this to

import System.IO

It looks from the documentation that the one embraces the other.  Something to look up.

>ghc main.hs -o helloname.exe
[1 of 1] Compiling Main             ( main.hs, main.o )
Linking helloname.exe ...


>helloname
Enter your name:
Rocky
Hello Rocky have a scone

Wednesday 20 May 2015

FizzBuzz

This example illustrates the use of the case construction.  An expression is  evaluated and the result is matched against a sequence of possible values to determine which further expression is to be evaluated to be the  return value of the whole expression.

The underscore character is a wildcard that matches anything.

The aim is to create the fizzbuzz functions, which takes a number and returns "Fizz" if the number is a multiple of 3, "Buzz" if the number is a multiple of 5, "Fizzbuzz" if the number is a multiple of 15, and otherwise just the number.

We can evaluate the mod of the number against both 3 and 5 at the top of the function and match the results in a tuple.  We don't have to check explicitly for a multiple of 15 because multiples of 15 are the numbers that are multiples of both 3 and 5.

fizzbuzz :: Int -> String
fizzbuzz x =
    case (x `mod` 3, x `mod` 5) of
      (0, 0) -> "Fizzbuzz"
      (0, _) -> "Fizz"
      (_, 0) -> "Buzz"
      (_, _) -> show x

You know that nagging feeling that there is a better way.  Caused by the fact that the text strings Fizz and Buzz show up in two places.

We can't return the number as the final clause of the function because the return value has to be a string - we use the function show to convert a string.

The command :load will load your code into the REPL.

Therefore the function fizzbuzz has type Int goes to string:

*Main> :t fizzbuzz
fizzbuzz :: Int -> String

And I can view thr fizzbuzzes from 1 to 100 in the REPL:

*Main> map fizzbuzz [1..100]
["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11",
"Fizz","13","14", "Fizzbuzz","16","17","Fizz","19","Buzz",
"Fizz","22","23","Fizz","Buzz","26", "Fizz","28","29",
"Fizzbuzz","31","32","Fizz","34","Buzz","Fizz","37","38",
"Fizz","Buzz","41","Fizz","43","44","Fizzbuzz","46",
"47","Fizz","49","Buzz", "Fizz","52","53","Fizz","Buzz",
"56","Fizz","58","59","Fizzbuzz","61","62",
"Fizz","64","Buzz","Fizz","67","68","Fizz","Buzz",
"71","Fizz","73","74" ,"Fizzbuzz","76","77","Fizz",
"79","Buzz","Fizz","82","83","Fizz","Buzz"
,"86","Fizz","88","89","Fizzbuzz","91",
"92","Fizz","94","Buzz","Fizz",
"97","98","Fizz","Buzz"]
*Main> 

OK, but instead of seeing these in the REPL I want to print them out.  Instead of mapping to a string I want to map fizzbuzz to an IO action that writes a string to the terminal, plus a line feed.  The library function I want is putStrLn:

*Main> :t putStrLn
putStrLn :: String -> IO ()

So the function to call fizzbuzz and get the IO action to write the reulting string to the screen is the combination of these, created by function composition operator which is a dot . thus

*Main> :t (putStrLn . fizzbuzz)
(putStrLn . fizzbuzz) :: Int -> IO ()

Right, so I want to map this combined function onto the integer list 1..100. We need the right version of the map function, though, this one:

*Main> :t mapM_
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()

So mapM_ will take our function that goes from an Integer to an IO action, apply this to a list of Integers, and give us back an IO action that we can plug straight into the main function, like this:

main :: IO ()
main = do
  mapM_ (putStrLn . fizzbuzz) [1..100]

fizzbuzz :: Int -> String
fizzbuzz x =
    case (x `mod` 3, x `mod` 5) of
      (0, 0) -> "Fizzbuzz"
      (0, _) -> "Fizz"
      (_, 0) -> "Buzz"
      (_, _) -> show x

So, in DOS:

>ghc fizzbuzz
[1 of 1] Compiling Main             ( fizzbuzz.hs, fizzbuzz.o )
Linking fizzbuzz.exe ...
>fizzbuzz
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
...
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz

Well, I got that right but only because I've been round this loop a few times before.

Infix and Prefix

You can turn infix operators such as + into prefix functions by putting then in brackets:

Prelude> 2 + 2
4
Prelude> (+) 2 2
4

Conversely you can take prefix functions and turn them into infix operators by
surrounding them with back ticks, thus:

Prelude> mod 12 5
2
Prelude> 12 `mod` 5
2

There is also a list comprehension syntax that works like this.  Imagine someone has just asked for the sum of all numbers in the range 1 to 999 that are either a multiple of 3 or a multiple of 5.  You can translate that pretty directly into Haskell:

Prelude> sum [x | x <- [1..999], mod x 3 == 0 || mod x 5 == 0]
233168

Interactive Haskell


When this is all installed you can run a REPL via GHCi which is the Glasgow Haskell Compiler Interactive and which opens up in a DOS box... or there is a Windows version of the same thing which opens in a regular Windows - er - window... and rather smoothly I find I can start the same thing inside Emacs.

In Emacs you can start the interpreter and load the file you're working in with C-c C-l, or just start the interactive mode with C-c C-b.

So, running the Haskell REPL, what can you do?

Firstly there are REPL commands: these start with a colon character.  So firstly you can change to the folder where your code is going to be:

GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :cd \users\polly\documents\projects\haskell
Prelude> :!dir
 Volume in drive C is Windows
 Volume Serial Number is 20F4-549E

 Directory of C:\users\polly\documents\projects\haskell

02/05/2015  11:12    <DIR>          .
02/05/2015  11:12    <DIR>          ..
02/05/2015  11:14               978 #notes.txt#
02/05/2015  10:47         1,950,052 hello.exe
02/05/2015  10:46               544 hello.hi
02/05/2015  10:44                31 hello.hs
02/05/2015  10:46             1,772 hello.o
02/05/2015  11:05               860 notes.txt
02/05/2015  10:56               354 notes.txt~
              11 File(s)      1,959,067 bytes
               2 Dir(s)  88,516,657,152 bytes free

In here you can load your file and run it by calling the main function:

Prelude> :load hello
Ok, modules loaded: Main.
Prelude Main> main
Hello World
Prelude Main>

What else can you do in here?  Your basic infix arithmetic operators:

Prelude Main> 2 + 2
4

Function calls require no syntax at all:

Prelude Main> sqrt 10
3.1622776601683795

Round brackets and commas give you tuples: functions fst (first) and snd (second)
work on two-element tuples:

Prelude Main> fst (1,2)
1
Prelude Main> snd (1,2)
2

Square brackets and commas give you lists, with : as the cons operator:

Prelude Main> 1 : [2,3,4]
[1,2,3,4]

The identifier it gives you the result of the previous operation:

Prelude Main> tail it
[2,3,4]
Prelude Main> head it
2

head is the CAR function and tail is the CDR.  Strings are lists of characters:

Prelude Main> head "Hello"
'H'
Prelude Main> tail "Hello"
"ello"

++ concatenated lists, including strings:

Prelude Main> 'H' : "ello"
"Hello"
Prelude Main> "H" ++ "ello"
"Hello"

You can try some functions on characters, if you first import the required library of character functions, so:

Prelude> import Data.Char
Prelude Data.Char> map toUpper "hello"
"HELLO"

The notation [x..y] gives you a list of elements in the range from x to y.

We have the familiar list operations map, filter and foldr (fold-right):

Prelude Main> map sqrt [1..10]
[1.0,1.4142135623730951,1.7320508075688772,2.0,2.23606797749979,2.44948974278317
8,2.6457513110645907,2.8284271247461903,3.0,3.1622776601683795]
Prelude Main> filter even [1..10]
[2,4,6,8,10]
Prelude Main> foldr (+) 0 [1..10]
55

The next most valuable REPL command is :t, which tells you the type of an expression.

Hello World Again!

The Haskell team have done what the Erlang guys did - created a single block of resources that can be downloaded as a massive package that gives you everything you need to get started.

Via www.haskell.org there is a "Haskell Platform" that takes the form of a 130 MB download - not long ago I would not have had room to store that much, let alone consider downloading it - -

This gives you a setup.exe that installs the toolkit.  Solution.  Platform.

Well also I will need the Haskell mode for Emacs but I find I have this already. I can't remember where I got this from, I've copied the files over from another machine from one of the previous times that I decided finally to learn Haskell and never got anywhere. Twas ever thus.

Anyway, the minimum Hello World program in Haskell looks like this:

main = putStrLn "Hello World"

main of course indicates to the compiler that this is the entry point of the code: and all we do is call a function that emits a given string to the terminal.

I've put this in a file called hello.hs

To compile, start DOS:

Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.
C:\Users\polly>cd documents\projects\haskell
C:\Users\polly\Documents\projects\haskell>prompt $G
>dir
 Volume in drive C is Windows
 Volume Serial Number is 20F4-549E

 Directory of C:\Users\polly\Documents\projects\haskell

02/05/2015  11:24    <DIR>          .
02/05/2015  11:24    <DIR>          ..
02/05/2015  11:25             2,397 #notes.txt#
02/05/2015  11:24                31 hello.hs
02/05/2015  11:17             2,024 notes.txt
02/05/2015  11:05               860 notes.txt~
               8 File(s)          9,788 bytes
               2 Dir(s)  88,518,500,352 bytes free

>ghc --make hello.hs -o hello.exe
[1 of 1] Compiling Main             ( hello.hs, hello.o )
Linking hello.exe ...

ghc is the compiler: we supply the source file name and the name of the executable (flag -o) that we want to create.  Results:

>dir
 Volume in drive C is Windows
 Volume Serial Number is 20F4-549E

 Directory of C:\Users\polly\Documents\projects\haskell

02/05/2015  11:27    <DIR>          .
02/05/2015  11:27    <DIR>          ..
02/05/2015  11:25             2,397 #notes.txt#
02/05/2015  11:27         1,950,052 hello.exe
02/05/2015  11:27               544 hello.hi
02/05/2015  11:24                31 hello.hs
02/05/2015  11:27             1,772 hello.o
02/05/2015  11:17             2,024 notes.txt
02/05/2015  11:05               860 notes.txt~
              11 File(s)      1,962,156 bytes
               2 Dir(s)  88,516,456,448 bytes free

And then we can run it:

>hello
Hello World