CS54 - Fall 2022 - Class 1

Example code in this lecture

   power.sml

Lecture notes

  • PERM list, etc.

  • CS51, CS54 and CS62: how it all fits together
       - Who should be here?
          - taken CS51
          - taken AP CS
          - something similar and have gotten approval from a CS faculty member

  • course overview

  • Course web page: http://www.cs.pomona.edu/classes/cs54/
       - Use Piazza (I'll have you all registered soon!)
       - Mentor sessions
          - Use them to get help *if* you get stuck
          - These are NOT required
          - Work before coming to the session
          - The earlier sessions will be *much* less crowded and you'll get better support
       - Course readings
          - Won't be extensive reading, but do read the handouts as I suggest
       - Course schedule

  • Administrative: http://www.cs.pomona.edu/classes/cs54/syllabus.html

  • Assignment 0
       - Posted and due Friday at 5pm
       - Key part: getting SML working for you!
          - Start ASAP on getting it installed
          - Installation instructions on the course webpage
          - Corey (the CS dept sysadmin) will have office hours in Edmunds 218 (upstairs): Wednesday, 1-2:30pm and 4-5pm (before and after class)
       - laptops
          - You have access to all of the CS labs. They have everything installed
          - You may also use your laptop for this class, but you'll have to set it up with SML and a few other things installed.

  • Background
       - Who took CS51?
          - How many know python?
       - Who took AP?
          - How many know Java?
       - How many know SML?
          - Another functional language?

  • Two ways of interacting with SML
       1) the interpreter
          - Type commands and get back results
          - Nice for testing things out and doing simple things
          - I'll use this a lot in class
       2) by editing a file and then running in the interpreter
          - Much more useful when writing actual programs
          - Same as if you'd typed the commands into the interpreter

  • To start SML you first open Terminal, which is a shell (if you're using Windows, you'll install and use cygwin)
       - What can you do in the shell?
          - almost everything you can do with the GUI (i.e. the windows environment)
          - navigate the file system
          - edit files
          - run programs
          - ...
       - then just type sml and you'll see:
          Standard ML of New Jersey v110.69 [built: Mon Jun 8 23:24:21 2009]
          \-

          (The dash is the statement prompt from SML, though I'll often use '>' in my notes)

  • Your first SML function
       > fun add1 x = x + 1;
       val add1 = fn : int -> int

       - The syntax for declaring a function is:
          fun <name_of_function> <arguments> = <function_body>;

          - it looks a bit more like declaring a mathematical function
       - What do you think: "val add1 = fn : int -> int" is?
          - This is the response from SML saying that it has defined a new value
             - The responses can always be broken down as follows:

                val <variable_name> = <value> : <type>
          - The name of the value is add1
          - fn tells us it's a function
          - int -> int is the type of the function
       - This already tells us some interesting things about SML:
          - functions are "first-class entities" in SML. They are treated like any other *value* in the language (ints, strings, etc.)
             - they can be stored to variables
             - they can be passed as arguments to other functions
             - they can be returned from functions
          - int -> int
             - this says that the function takes an integer as a parameter and returns an integer
             - How did SML know this?
                - Everything in SML has a type
                   - this is called a "strongly-typed" language
                   - values have a type
                   - functions, therefore, also have a type
                   - operators (like +, -, *, etc.) have a type as well
                - SML has a *very* good type inference system
                   - + we know is used on numbers
                   - therefore, x must be a number
                   - therefore the function both takes and returns a number
       
  • Using a function
       - Once we've declared a function, we can use it
       > add1 10;
       val it = 11 : int

       - As before, the response from SML can be broken down:
          - name of the variable: it
             - what do you think "it" is?
                - name for the previous statement when we don't assign it to a value
                   - can actually use it if you'd like in the next statement
          - value is 11
          - type of the value is int
          - get used to looking at the response and understanding it!

       - Anything interesting about how we called the function?
          - no parentheses!
             - we could have added them, but for style reasons we won't put them in
          - like Java, we will terminate all statements with a semi-colon

  • The power function
       - We'd like to write a function called power that takes two numbers, n and k, and produces n^k
       - Write this in python (or Java), recursively:
          def power(n, k):
           if n == 0:
           return 1
           else:
           return n * power(n, k-1)
       - in Java:
          public static int power(int n, int k){
             if( n == 0 ){
                return 1
             }else{
                return n * power(n, k-1)
             }
          }
       
       - look at the power function in power.sml code
          - now I'm using sublime to view the file (you can use any text editor you'd like, but I recommend something with syntax highlighting)
          - like before, we use "fun" to define a new function
          - what's different?
             - we're not using if/else like in python/Java
          - SML uses "patterns" to match different input cases
             - it can do many things, like match constants (e.g. 0), but not everything (e.g. match all negative numbers)
             - pattern matching starts at the top and works down. When it finds one that matches, it executes that code and only that code
                - for example, the order in the power function *does* matter. If we'd put (n,k) first, the (n,0) case would never be reached

  • Using the function
       - We can type this (or copy and paste this) into the SML window and we get the following response:
          val power = fn : int * int -> int

       - Anything new here?
          - the input type to the function is "int * int"
             - this is called a "tuple"
                - a tuple is a combination of two or more values (like in python!)
                - they are defined by putting comma separated values inside parentheses
                   > (1, 2);
                   val it = (1,2) : int * int
             - the function only has one input
                - in fact, technically, all functions in SML only have one input!
       
       - to call it we give it a tuple:
          > power (10, 2);
          val it = 100 : int

  • loading files
       - the SML interpreter is nice for doing interactive things and debugging, but we don't want to keep copying and pasting code into the SML interpreter
       - use
          - we can run the contents of an entire file through using "use", e.g.

             > use "power_alone.sml";
             val power = fn : int * int -> int
             val it = () : unit

          - it behaves as if you started at the top of the file and typed each of the lines one at a time
          - you'll see the output from the SML for each line
          - additionally, you'll see one last line at the end which is the "result" from the actual use command
       - most of the time this is how you will work:
          - edit your function(s) in your text editor
          - *save* the file
          - "use" the file
          - try out some of the functions in the interpreter
          - repeat

  • A better power function
       - Any problems with the power function?
          - Doesn't handle negative numbers
       - How could we fix this?

  • Look at the power2 function in power.sml code
       - We now have three patterns in the function
          1) for when k = 0
          2) for when n = 0 (strictly, this could be handled by the third case)
          3) the general case

       - the if-then-else statement is used to handle the case where k < 0
          - notice that if-then-else represents a value
             - each branch has a value of the same type
             - no matter what branch we go down, we obtain a value
             - we'll see this type of behavior A LOT