Hello, World!

PA 0 — Due: Fri Sep 29 11pm CT

The following is adapted from a post originally written by Brian Hempel.

In this warmup assignment, you will set up your development environment for this course, and then practice making a submission to your Github Classroom repository. Whereas subsequent weekly programming assignments will be worth 10 points each, PA 0 is worth 1 point. Subsequent PAs will be released (at least) one week before they are due; this setup assignment is due sooner.

For this course, you will want four things on your computer:

  1. A terminal for compiling and running code.

  2. A good text editor for writing code.

  3. The latest stable version of Haskell (currently 9.2.8 or higher, or 9.4.7 or higher, or 9.6.2 or higher).

  4. Git for tracking changes in your code and submitting assignments.

Terminal

Compiling and running Haskell programs generally happens on the command line, so you’ll need to have a terminal application.

All macOS machines come with an app called “Terminal” installed. A popular alternative is iTerm.

On Windows, if you don’t have a terminal you’ll get one for free when you install git below (it will be called “Git Bash”).

Terminal Basics

You will want to develop some comfort on the command line. Here are the bare essentials:

See where you are (“print working directory”):

$ pwd

(The $ above is just an indication that you’re on a command line. All you have to type is pwd.)

List what’s in this folder:

$ ls

List “all” files (files that begin with . are usually hidden), with “long” information:

$ ls -al

Learn about any command by looking at its man page (manual page):

$ man ls

(Hit q to quit.)

Enter a folder (“change directory”):

$ cd some_folder

Go up one folder:

$ cd ..

The “root” folder is /, and your home directory is ~.

Make a folder:

$ mkdir new_directory

Move (or rename!) a file or folder:

$ mv old_name new_name

Copy:

$ cp old_file new_file

Copy a folder (“recursive” copy):

$ cp -r old_folder new_folder

Log on to a remote machine:

$ ssh username@computername.cs.uchicago.edu

Each computer’s name is written on the side of the machine. Or, there are a few machines for shared use. You can leave SSH with ctrl-d on Mac and Linux and ctrl-z then <Enter> for Windows.

Copy a file to another machine:

$ scp some_file username@computername.cs.uchicago.edu:~/some/path/on/other/machine

If you use a terminal text editor like emacs or vim, you can use ssh to do your homework remotely (although the University may soon require a VPN for using SSH off-campus).

If some app is running in a terminal and you want it to stop, hit ctrl-c. If some app in the terminal is asking you for input and you don’t want to give it any, hit ctrl-d (end of input). ctrl-d is also a way to end your terminal session.

Text Editor

Microsoft Word ain’t gonna cut it. You want a text editor that makes your code colorful and automatically indents every new line you type.

Visual Studio Code is a popular GUI text editor these days. The lab machines have Sublime Text installed. For VS Code: install the Haskell extension and you will be rewarded with many nice editor features.

On the command line, the popular options are vim and emacs. Both these editors are pre-installed on the lab computers. Using a command-line editor takes some practice, but an experienced user can learn to rapidly perform complicated edits. Another advantage is that these editors can be used on remote machines over SSH. The main disadvantage is you can’t use your mouse.

Also, if you haven’t already maximized your key-repeat rate yet in your keyboard settings, you’ll thank yourself later for doing it now. You’ll quickly get used to it and it will save you days worth of time.

Haskell

You can install Haskell onto your own machine using these instructions. Choose the defaults whenever GHCup asks in purple text “Do you want to…?”. We will probably not use Haskell Tool Stack, so you may skip installing “stack” if prompted.

Mac users may need to first install the XCode command line tools. There should be a dialog that pops up asking you to do it. But if not, you can run:

$ xcode-select --install

To see if you have Haskell installed correctly, open up a Terminal and run:

$ ghci --version
The Glorious Glasgow Haskell Compilation System, version 9.2.5

If your version of GHCi is not of the latest stable versions mentioned above, then you may have to troubleshoot. For Mac users, run the command

echo $PATH

and check that ~/.ghcup/bin and ~/.cabal/bin appear. If not, you might have to add these to your path. If you have the file ~/.profile or ~/.bash_profile, you can run the following:

$ echo 'PATH=~/.ghcup/bin:~/.cabal/bin:$PATH' >> ~/.bash_profile

(If you are using macOS Catalina or later, it is likely that your default shell is Z Shell (Zsh), not Bash. You should be able to tell by checking if the top of the Terminal app window says zsh. If this is the case, replace ~/.bash_profile with ~/.zshrc above.)

Restart the terminal and try again. Then test GHCi with a couple arithmetic commands:

$ ghci
GHCi, version 9.2.5: https://www.haskell.org/ghc/  :? for help
ghci> 2 + 2
4
ghci> 8 ^ 10
1073741824

Usually on a terminal you stop a program by typing ctrl-c, but in GHCi ctrl-c will only stop a long-running line of code. Instead, you leave GHCi by typing ctrl-d, which means “End of Input”. You can also leave GHCi by typing :q and hitting return.

(For non-Mac users (especially Windows users) you may have to consult Stack Overflow and help each other for troubleshooting. None of the instructors/TAs are particularly familiar with Windows, but we can try to help the best we can!)

Git

Git (pronounced like “get”) is a version control system. Git lets you take snapshots of an entire folder and stores the snapshots as “commits”. With git you can:

To use technical terms, Git is a distributed version control system. Because of its speed and flexibility, it has become the leading tool for managing source code. For example, GitHub is the world’s largest storehouse of open source projects. However, GitHub did not make Git—that honor goes to Linus Torvalds, who you may recognize as the creator of Linux.

If you’re looking for a version control system to learn in 2022, Git is the one. You won’t be using many of its features (for example, you won’t be collaborating with each other), but you will use Git to submit code and that will give you a taste of what you can do.

You can download git here. Mac OS X computers may already have git installed.

Verify Git Installation

To check if you have git installed, run this command on the command line:

$ which git

You should see a path, like:

/usr/local/bin/git

If you do, you’re good to set up git.

A Bit of Git Setup

Check your Git config and see if you have a name and email set.

$ git config --list

If you don’t have a name and email set, choose the name and email that will appear on all your commits. You do not have to use your UChicago email.

$ git config --global user.name "Name"
$ git config --global user.email "email@example.com"

Enable color to be happier:

$ git config --global color.ui auto

Getting Your Repository

We will use GitHub Classroom to create git repositories for you, one per assignment—this will make it slightly easier for us to distribute starter code and feedback on your submissions.

To start, check Ed for the post containing the GitHub Classroom invitation link for PA 0. When you follow that link and accept the invitation—you will need to sign in to GitHub with the USERNAME that you registered in our pre-course survey—a PA 0 repository will be created for you. (Each programming assignment will start this way: check Ed, accept the GitHub Classroom invitation.)

On the command line, navigate to your folder for this class. Now, clone your PA 0 repository from the submission system onto your computer:

$ git clone https://github.com/UChicago-PL/cs223-fa23-pa-0-hello-world-USERNAME.git
$ cd cs223-fa23-pa-0-hello-world-USERNAME

Note: Some Mac users have reported trouble cloning into an iCloud directory. Clone outside of iCloud.

There is also a web interface to your repository. Log in to https://github.com/UChicago-PL/ to ensure you can see your repository. After pushing changes, it’s often best to check on the web to make sure you pushed everything—because what you see on the web is what we see when we grade.

SSH Keys and PATs

If you encounter this error…

Cloning into 'cs223-TERM-pa-0-hello-world-USERNAME'...
Username for 'https://github.com': USERNAME
Password for 'https://USERNAME@github.com': XXX
remote: Support for password authentication was removed on August 13, 2021.
remote: Please see ... for information on currently recommended modes of authentication.
fatal: Authentication failed for ...

… follow that link for information about how to set up an SSH key or personal access token. (While “classic” PATs are not the most recommended option, they are next simplest compared to password authentication.)

Some Git Practice

Let’s make sure Haskell is working and practice Git’s workflow.

There should be a Hello.hs file in your PA 0 repository, which looks something like:

data Level
  = Undergraduate
  | Masters
  | PhD
  | Other
      deriving Show

name :: String
name = "Your name here"

level :: Level
level = Undergraduate

major :: String
major = "Your major or program here"

why :: String
why = "A sentence about what inspired you to..."

distance :: Int -> Int -> Int
distance rate time = rate * time

Put in your own answers for name, level, major, and why. Make sure to save the file Hello.hs.

On the command line, start GHCi by typing:

$ ghci

You should see ghci>. (If you see Prelude> instead, you are probably using an older version of Haskell.) To load the file, use :l (the letter l).

ghci> :l Hello

You should see:

ghci> :l Hello
[1 of 1] Compiling Main             ( Hello.hs, interpreted )
Ok, 1 module loaded.
ghci>

You can now use the items you defined.

ghci> name
"Chuck Norris"
ghci> level
Other
ghci> distance 15 20
300

There’s a still another modification we’ll make below, but it’s a good idea to submit your changes as you work.

Exit GHCi by hitting ctrl-d. Then run:

$ git status

You should see something like:

On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   Hello.hs

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    .Hello.hs.swp

no changes added to commit (use "git add" and/or "git commit -a")

Git is telling you that it’s not watching the Hello.hs.swp file (a temp file generated by vim). Any changes to this file will be ignored. And it’s telling you that it is tracking the file Hello.hs but that your changes to the file have not yet been tracked.

Tell Git to track your changes with git add.

$ git add Hello.hs

Now if you run git status you should see something like:

On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   Hello.hs

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    .Hello.hs.swp

We haven’t actually created a snapshot (a commit). We’re just telling Git what files we want to include in the commit. If we had more files, we could also add them to create a single big snapshot with multiple files.

Let’s just make a commit with this file.

$ git commit -m "Hello.hs with some personal info"

The string after -m is your message for the commit. It’s sort of a name for the snapshot. Use it to describe what you changed since the last commit.

You can see a log of commits with git log:

$ git log
commit 30a672d7a3b3f615080a7fd79eccaa831f5285dc
Author: Brian Hempel <brianhempel@uchicago.edu>
Date:   Mon Oct 31 22:46:35 2016 -0500

    Hello.hs with some personal info

The commit is still only on your own computer. To push this change to the remote repository (the mit.cs.uchicago.edu server that’s acting as our submission system), just type:

$ git push

(For your very first push, you may have to type git push -u origin main.)

You should see a message about pushing to main.

Okay, now it’s time to make a bigger change. Open Hello.hs and paste this code at the bottom, updating the existing definition of main, if any:

main :: IO ()
main = do
  putStrLn "Hello, world!"
  putStrLn ""
  putStrLn ("My name is " ++ name ++ ".")
  putStrLn ("I am a " ++ show level ++ " student.")
  putStrLn ("I'm studying " ++ major ++ ".")
  putStrLn ("I'm in this class because " ++ why)
  putStrLn ""
  putStrLn $
    "If you travel 15mph for 30 hours you will go " ++
    show (distance 15 30) ++ " miles."

Reload the file with :r (the letter r), and try it out:

$ ghci
ghci> :r
ghci> main

You should see output.

Now exit GHCi, and try compiling (rather than interpreting) the file with:

$ ghc Hello.hs

GHC should produce an executable in the same folder called Hello.

Run it:

$ ./Hello

You should see output. You’ve just compiled your first working Haskell executable!

Now, let’s commit this change.

Use git diff to see any changes that we haven’t told Git we want to commit. (Note, this shows changes in tracked files only; Hello.hs is tracked because we already committed it.)

$ git diff
...

 main :: IO ()
 main = do
   putStrLn "Hello, world!"
+  putStrLn ""
+  putStrLn ("My name is " ++ name ++ ".")
+  putStrLn ("I am a " ++ show level ++ " student.")
+  putStrLn ("I'm going into " ++ major ++ ".")
+  putStrLn ("I'm in this class because " ++ why)
+  putStrLn ""
+  putStrLn $
+    "If you travel 15mph for 30 hours you will go " ++
+    show (distance 15 30) ++ " miles."

Or, you can see a summary with git status:

On branch main
Your branch is up to date with 'origin/main'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
    modified:   Hello.hs

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    .Hello.hs.swo
    Hello
    Hello.hi
    Hello.o

no changes added to commit (use "git add" and/or "git commit -a")

The Hello executable and a few intermediate files created by Haskell are untracked. Let’s let them be and not commit them.

But we do want to commit our change to Hello.hs. Tell Git to include our change in our next commit:

$ git add Hello.hs

Now, actually make the commit:

$ git commit -m "Print out my info"

If you run git log, you will now see two commits:

$ git log
commit 32133475e7e83c3ba4017787f4c0d56aab35f058
Author: Brian Hempel <brianhempel@uchicago.edu>
Date:   Mon Oct 31 23:01:02 2016 -0500

    Print out my info

commit 30a672d7a3b3f615080a7fd79eccaa831f5285dc
Author: Brian Hempel <brianhempel@uchicago.edu>
Date:   Mon Oct 31 22:46:35 2016 -0500

    Hello.hs with some personal info

The “Print out my info” commit is still only on your computer.

$ git push

There you go! If your Hello.hs file looks right on GitHub, you’ve successfully pushed. Push early and push often.

Grades and Feedback

Each week, when you think your submission is final, you should verify that your changes were pushed:

  1. Run git status to make sure you don’t have any local changes.
  2. Check your repo on GitHub. Make sure you are on the main branch and that your files look right.

If everything looks good, your submission is done. An automated script will grab your repository at the deadline.

There’s one more thing you should know. Your instructor or the graders may distribute grades by making changes to your remote repository. When there are more commits on the remote repository than on your local repository, Git will not let you push.

You have to first run:

$ git pull

This will pull any commits from the remote repository and automatically merge them with your local changes.

A vim session may open with a commit message saying “Merge … into main”. Save the message and exit vim by hitting :x (colon x).

Afterwards you can run:

$ git push

In addition to new files for grade reports, feedback may also be provided as GitHub comments on Pull Requests, as opposed to files in the repository. Stay tuned for more details.

In the exercise above, we ran ghc directly to compile our code into an executable. This works great for small and simple projects with minimal dependencies. But soon, we will start using a system called Cabal to build our code. During the course, we will encounter and use only a few basic commands. For now, let’s just make sure Cabal is up and running.

Go somewhere, make a new directory, and then run cabal init:

$ cd SOMEWHERE
$ mkdir my-first-haskell-project
$ cabal init --non-interactive
...
Generating CHANGELOG.md...
Generating app/Main.hs...
Generating my-first-haskell-project.cabal...
...

Take a look at the files and folders created, notably:

my-first-haskell-project/
  my-first-haskell-project.cabal
  app/
    Main.hs

You can build…

$ cabal build

… and run:

$ cabal run
Up to date
Hello, Haskell!

Start poking around the .cabal file to see what it looks like. To learn a little more about what goes into this file, create a new directory and run cabal init --interactive instead.

Git Miscellanea (Optional)

Graphical Tools

For the git add and git commit part of the workflow, a GUI tool may help (I, Brian, use the Mac-only GitX). A GUI helps visualize changes much better. There are equivalent tools for other operating systems. Git comes with gitk, which you might try.

Documentation

There are man pages documenting the different git commands, e.g.:

$ man git-add
$ man git-diff
$ man git-commit
$ man git-pull
...

Or:

$ git help add
$ git help diff
...

These docs describe an interactive mode for git add that you might find useful:

$ git add -i

*** Commands ***
  1: status   2: update   3: revert   4: add untracked
  5: patch    6: diff     7: quit     8: help
What now>

Of course, you can also search online for tutorials, for example Learn Git Branching and Try Git. (Though we don’t recommend using branches during this course—you don’t want to accidentally forget to push main and fail your assignment!)

More Commands

The above commands are all you should need for this class, but in the future you may want to learn more about what you can do with Git.

Git gives you complete flexibility. You can grab old versions of files. You can undo entire commits. You can work on different branches to separate different features while you are working on them. You can reorder commits. You can go back in time and change history. (However, a rule of thumb is that you should not rewrite history after pushing.)

For what it’s worth, these are the commands I (Brian) use in my programming workflow. More advanced users may find these interesting. For this course, multiple branches or rewriting history is not recommended.

git add --patch              # Actually via GitX; but `git add -p` is close
git rm                       # Un-stage a change so it's not committed
git commit                   # Again, via GitX
git commit --amend           # Change last commit (GitX again)
git commit -a -m "wip"       # WIP commits better than stashing. Never stash
git reset HEAD^              # Un-commit a WIP commit (but keep changes)
git checkout file_name       # Discard changes to file
git checkout -b branch_name  # New branch
git branch -d branch_name    # Delete a branch
git pull --rebase            # Pull, then re-apply local commits
git rebase branch_name       # Replay commits on top of branch
git cherry-pick              # Apply a single commit from a different branch
git reflog                   # Recover deleted branches, mistaken hard resets

git rebase --interactive HEAD^^^^^^    # Clean up history before pushing!