Plus a few random things

Slides:



Advertisements
Similar presentations
CMSC 330: Organization of Programming Languages Tuples, Types, Conditionals and Recursion or “How many different OCaml topics can we cover in a single.
Advertisements

More about functions Plus a few random things. 2 Tail recursion A function is said to be tail recursive if the recursive call is the very last thing it.
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
1 Gentle Introduction to Programming Session 2: Functions.
© Copyright 1992–2004 by Deitel & Associates, Inc. and Pearson Education Inc. All Rights Reserved. Chapter 5 - Functions Outline 5.1Introduction 5.2Program.
Methods. Why methods? A method gives a name to something that you want to do, so you don’t have to think about how to do it, you just do it The name should.
Pattern matching. The if expression The else part of an if expression is optional if ( condition ) expression1 else expression2 If the condition evaluates.
© Copyright 1992–2004 by Deitel & Associates, Inc. and Pearson Education Inc. All Rights Reserved. C How To Program - 4th edition Deitels Class 05 University.
Fall Week 3 CSCI-141 Scott C. Johnson.  Say we want to draw the following figure ◦ How would we go about doing this?
Haskell. 2 GHC and HUGS Haskell 98 is the current version of Haskell GHC (Glasgow Haskell Compiler, version 7.4.1) is the version of Haskell I am using.
Loops: Handling Infinite Processes CS 21a: Introduction to Computing I First Semester,
224 3/30/98 CSE 143 Recursion [Sections 6.1, ]
Python uses boolean variables to evaluate conditions. The boolean values True and False are returned when an expression is compared or evaluated.
Copyright Curt Hill The C/C++ switch Statement A multi-path decision statement.
Monads. foo1 Method to print a string, then return its length: scala> def foo1(bar: String) = { | println(bar) | bar.size | } foo1: (bar: String)Int scala>
FUNCTIONS. Midterm questions (1-10) review 1. Every line in a C program should end with a semicolon. 2. In C language lowercase letters are significant.
CSIS 113A Lecture 5 Functions. Introduction to Functions  Building Blocks of Programs  Other terminology in other languages:  Procedures, subprograms,
Quiz 3 Topics Functions – using and writing. Lists: –operators used with lists. –keywords used with lists. –BIF’s used with lists. –list methods. Loops.
CSC 1010 Programming for All Lecture 5 Functions Some material based on material from Marty Stepp, Instructor, University of Washington.
Lets and Loops Tail Recursion.
String and Lists Dr. José M. Reyes Álamo.
Chapter 9: Value-Returning Functions
Programming what is C++
User-Written Functions
Instant Scala.
Recursion DRILL: Please take out your notes on Recursion
Lesson #6 Modular Programming and Functions.
COMP 170 – Introduction to Object Oriented Programming
Lesson #6 Modular Programming and Functions.
CS-104 Final Exam Review Victor Norman.
Principles of programming languages 4: Parameter passing, Scope rules
Haskell.
Repeating code We could repeat code we need more than once: i = 1 print (i) i += 1 print (i) #… stop when i == 9 But each line means an extra line we might.
Functions.
Chapter 5 - Functions Outline 5.1 Introduction
Lesson #6 Modular Programming and Functions.
Functions Chapter 9 Copyright © 2008 W. W. Norton & Company. 1
Strings, Line-by-line I/O, Functions, Call-by-Reference, Call-by-Value
Important Concepts from Clojure
Control Structures (Structured Programming) for controlling the procedural aspects of programming CS1110 – Kaminski.
Important Concepts from Clojure
Haskell Dealing with impurity 30-Nov-18.
FP Foundations, Scheme In Text: Chapter 14.
CISC101 Reminders Assn 3 due tomorrow, 7pm.
Plus a few random things
Functions Chapter 9 Copyright © 2008 W. W. Norton & Company.
Coding Concepts (Basics)
Cases and Classes and Case Classes
String and Lists Dr. José M. Reyes Álamo.
C Programming Getting started Variables Basic C operators Conditionals
6.001 SICP Variations on a Scheme
Lesson #6 Modular Programming and Functions.
The Java switch Statement
Recursion Taken from notes by Dr. Neil Moore
Important Concepts from Clojure
The structure of programming
Plus a few random things
Control Structures (Structured Programming) for controlling the procedural aspects of programming CS1110 – Kaminski.
The structure of programming
Common Lisp II.
CISC101 Reminders Assignment 3 due today.
Thinking procedurally
Plus a few random things
Monads.
Plus a few random things
Lecture 3 More on Flow Control, More on Functions,
Functions, Procedures, and Abstraction
四時讀書樂 (春) ~ 翁森 山光照檻水繞廊,舞雩歸詠春風香。 好鳥枝頭亦朋友,落花水面皆文章。 蹉跎莫遣韶光老,人生唯有讀書好。
 A function is a named sequence of statement(s) that performs a computation. It contains  line of code(s) that are executed sequentially from top.
Plus a few random things
Presentation transcript:

Plus a few random things More about functions Plus a few random things

Tail recursion A function is said to be tail recursive if the recursive call is the very last thing it does, in any recursive branch Example #1: def collatz(n: Int): Int = { if (n == 1) 1 else if (n % 2 == 0) collatz(n / 2) else collatz(3 * n + 1) } There is no recursion if n == 1 In each other case, the last operation is a recursive call A good compiler can replace tail recursion with a loop def collatz(n: Int): Int = { var nn = n while (nn != 1) { if (nn % 2 == 0) nn = nn / 2 else nn = 3 * nn + 1 } nn } This is desirable because loops don’t cause the stack to grow

Factorial Here’s everybody’s first recursive function: def factorial(n: Long): Long = { if (n == 0 || n == 1) 1 else n * factorial(n - 1) } This is not tail recursive, because there is a multiplication that is performed after the recursive call Can the factorial function be rewritten to be tail recursive? Yes it can, and the technique for doing so can be applied to a lot of other functions, so it’s worth learning I’ll leave this as an exercise, since if you figure it out yourself you are much more likely to remember how to do it Here are three hints, which you can uncover one at at time if you get stuck (the text is white; select it and change the color) Use two functions; the second one should do all the recursive work The second function should have two parameters One of the parameters should be 1

Currying Here’s a function to find the hypotenuse of a right triangle: def hyp(a: Double, b: Double) = sqrt(a * a + b * b) Suppose you were to call it this way: val h = hyp(5.0, 12.0) You can think of this as the compiler substituting a value for each variable Suppose we substitute 5.0 for a first: sqrt(a * a + b * b) becomes sqrt(5.0 * 5.0 + b * b) And afterwards substitute 12.0 for b: sqrt(5.0 * 5.0 + b * b) becomes sqrt(5.0 * 5.0 + 12.0 * 12.0) which is then calculated (giving 13.0) Now suppose we stop after step 1 What we have after step 1 is a partially applied function Currying is a way to make partially applied functions

Currying in Scala Instead of giving our hyp function one parameter list, we can give it two parameter lists: scala> def hyp(a: Double)(b: Double) = sqrt(a * a + b * b) hyp: (a: Double)(b: Double)Double Now when we call it, we have to give it two argument lists, not just one list with two arguments: scala> hyp(5)(12) res2: Double = 13.0 We can stop with just the first list (but we need to use an underscore to tell Scala we know we left something out) scala> val h5 = hyp(5) _ h5: (Double) => Double = <function1> scala> h5(12) res3: Double = 13.0 With more parameters, we can break up the parameter list any way we like def foo(a: Int)(b: Int, c: String)(d: Double) = {...}

Another way to curry Here’s a function written in the usual way: scala> def avg(a: Double, b: Double) = (a + b) /2.0 avg: (a: Double,b: Double)Double Here we’re calling it in the usual way: scala> avg(5, 12) res6: Double = 8.5 Here we’re calling it with the first argument specified (5) but the second argument unspecified (_) scala> val a5 = avg(5, _: Double) a5: (Double) => Double = <function1> Notice that we had to specify the type of the omitted parameter Also pay careful attention to the type of the result Now let’s call our new, curried function: scala> a5(12) res7: Double = 8.5

Repeated parameters The last formal parameter may have a star after it, indicating zero or more values may be supplied scala> def echo(ss: String*) = for (s <- ss) println(s) echo: (ss: String*)Unit scala> echo("John", "Mary") John Mary scala> echo() // no output Inside the method, the repeated parameter is treated as an array; however, you can’t call the method with a sequence unless you use the following notation: scala> val list = List("able", "baker") list: List[String] = List(able, baker) scala> echo(list) <console>:10: error: type mismatch; // several additional lines scala> echo(list: _*) able baker

Named arguments Arguments may be supplied in any order if the parameter names are used in the call scala> def print2(a: Int, b: Int) = println(a + " " + b) print2: (a: Int, b: Int)Unit scala> print2(b=5, a=3) 3 5 If both named and positional arguments are used in a method call, the positional ones must come first

Default parameter values You can specify default values for parameters scala> def printTimes(s: String, n: Int = 1) { | for (i <- 1 to n) println(s) | } printTimes: (s: String, n: Int)Unit scala> printTimes("Hello, world!", 3) Hello, world! Hello, world! Hello, world! scala> printTimes("Hello, world!") Hello, world!

Call-by-name parameters When using a function as a argument, the function parameter is used only when requested: Example: def foo(f: Int => Int) { println("In foo with " + f(10)) } foo(factorial) // prints "In foo with 3628800" Other types of parameters are first evaluated, then their values are passed into the function: Example: def foo(n: Long) { println(n} } foo(factorial(10)) What is passed into the function is the number 3628800 By using => as the first part of the type in a function definition, the function will treat a parameter as a function Example: def foo(f: => Int) { println("In foo with " + f(10)) } foo(factorial) // prints "In foo with 3628800" This is an example of call-by-name

Lazy evaluation Lazy evaluation is a technique whereby a computation is not actually performed until and unless the result is needed lazy val xxx = someLongAndExpensiveComputation ... if (we decide that we need xxx) { use xxx // The computation is done here } Ranges in Scala are lazy scala> println((1 to Int.MaxValue) take 3) Range(1, 2, 3) The Stream class supports lazy evaluation, and therefore allows “infinite” data structures (example from Programming Scala by Wampler & Payne) scala> lazy val fib: Stream[Int] = Stream.cons(0, Stream.cons(1, fib.zip(fib.tail).map(p => p._1 + p._2))) fib: Stream[Int] = <lazy> cons is like :: scala> fib.take(10).print 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, empty

Building control structures When calling a curried function, you can replace the last set of parentheses with braces scala> hyp(5) { 12 } res27: Double = 13.0 You can only put expressions inside parentheses, but you can put multiple “statements” inside braces This, plus currying, plus lazy evaluation, allows you to build your own control structures scala> def repeat(n: Int)(body: => Unit) { | for (i <- 1 to n) body | } repeat: (n: Int)(body: => Unit)Unit scala> repeat(3) { | println("Hello") | } Hello Hello Hello

XML XML is built into Scala as a data type—not just as something supported by some package scala> val name = "Dave" name: java.lang.String = Dave scala> val x = <html><body><h1>Hello, {name}!</h1></body></html> x: scala.xml.Elem = <html><body><h1>Hello, Dave!</h1></body></html>

DSL Scala has superb support for Domain Specific Languages A parser combinator is a function that takes only other functions as parameters and returns only functions BNF is essentially built into Scala as a combinator library Example: Arithmetic expressions (adapted from Odersky, pp. 620-621) BNF: <expr> ::= <term> { “+” <term> | “-” <term> } <term> ::= <factor> { “*” <factor> | “/” <factor> } <factor> ::= <floatingPointNumber> | “(” <expr> “)” Scala (~ is used to indicate one thing follows another in sequence): import scala.util.parsing.combinator._ class Arith extends JavaTokenParsers { def expr: Parser[Any] = term ~ rep("+" ~ term | "-" ~ term) def term: Parser[Any] = factor ~ rep("*" ~ factor | "/" ~ factor) def factor: Parser[Any] = floatingPointNumber | "(" ~ expr ~ ")" }

The End