CPS 343/543 Lecture notes: Strong typing,
type inference, higherorder functions, and currying
Strong typing
 definitions vary
 a simple, but incomplete definition is:
`a stronglytyped programming language is one in which each name in a program
has a single type associated with it, and that type can be
determined at compile time' [COPL6] (i.e., by looking at the program)
not running it;
this means that all types are bound at compiletime (i.e., statically
bound)
 another, perhaps more general and all inclusive, definition is:
a stronglytyped programming language is one in which `type errors are always
detected' [COPL9]; means we must be able to determine the type of everything
just by looking at the program, and not by running it
 FORTRAN, C, and C++ are not strongly typed
 languages with coercion (e.g., FORTRAN, C, and C++ are
weakly typed)
 C and C++ use coercion, int x = 3.4;
 C and C++ support unions which are not type checked
 Ada is almost stronglytyped; the programmer can suspend type checking
 C# and Java (even though they are based on C/C++) are strongly typed
but have casting
 ML and Haskell are stronglytyped
 in safety, Haskell is the Java of functional programming languages
 why use a stronglytyped programming
language? reliability and safety
 why use a weaklytyped programming language? flexibility and efficiency
 LISP is said to be a typeless language
 ML comes with irremovable training wheels
34; (* works *)
(* 34.4; doesn't work *)
(* no coercion in ML, why? *)
real(3)4.4; (* this is a type cast *)
open Real;
Real.< (2.9, 3.0); (* Real is called a structure; open a class in OO *)
false andalso (1 / 0); (* doesn't work, why? *)
false andalso (1 div 0); (* still doesn't work, but not because of a divide by 0 *)
Type inference in Haskell
``In Haskell every expression must have a type, which is
calculated prior to evaluating the expression by a process
called type inference. The key to this process is a typing
rule for function application, which states that if f
is a function that maps arguments of type A to results of type
B, and e is an expression type A, then the
application f e has type B:
f :: A → B e :: A
f e :: B
For example, the typing not False :: Bool can be inferred from
this rule using the fact that not :: Bool → Bool
and False :: Bool'' [PIH].
Type inference in ML
key point: type inference gives us strong typing without explicit
type declarations
for more information, see [EMLP] p. 63
How ML deduces types: examples
(* the 0 returned in the first case
causes ML to use the type
"int list > int" for summing *)
fun summing (nil) = 0
 summing (x::xs) = x + summing (xs);
fun f1 (a, b) = if (a < b) then 3.0 else 2.0;
(* val f1 = fn : int * int > real *)
(*
fun f2 (a, b) = if (a < b) then 3.0 else 2;
stdIn:7.177.43 Error: types of if branches do not agree [literal]
then branch: real
else branch: int
in expression:
if a < b then 3.0 else 2
*)
fun f3 (a, b) = if (a + 0.0) < b then 1 else 2;
(* val f1 = fn : real * real > int *)
See [EMLP] §3.2.4 (pp. 6364) for more information.
Currying
 based on Kleene's S_{mn} theorem
(also called the translation lemma,
parameter theorem, or parameterization theorem) from
computability theory
 formally, states that for any function
f (x_{1}, x_{2}, ..., x_{n}),
f (a_{1}, a_{2}, ..., a_{m})
=
g (x_{m+1}, x_{m+2}, ..., x_{n}),
where m < n, such that
g (a_{m+1}, a_{m+2}, ..., a_{n}) =
f (a_{1}, a_{2}, ..., a_{m},
a_{m+1}, a_{m+2}, ...,
a_{n}).
Curried form in Haskell
 notice anything interesting?
Prelude> :t map
map :: (a > b) > [a] > [b]
Prelude> :t foldl
foldl :: (a > b > a) > a > [b] > a
Prelude> :t foldr
foldr :: (a > b > b) > b > [a] > b
Prelude>
pow (0, _) = 1
pow (1, b) = b
pow (_, 0) = 0
pow (e, b) = b * pow (e1, b)
powc 0 _ = 1
powc 1 b = b
powc _ 0 = 0
powc e b = b * powc (e1) b
Main> :t pow
pow :: (Num a, Num b) => (b,a) > a
Main> :t powc
powc :: (Num a, Num b) => b > a > a
Main>
square = powc 2
cube = powc 3
parenthesizing an operator converts it from an infix to prefix operator:
 called a 'section'
inc = (+) 1
inc1 = (+) 1.0
Main> :t inc
inc :: Integer > Integer
Main> :t inc1
inc1 :: Double > Double
Main>
 courtesy [PIH] p. 118
 currying obviates the need for
 the helper function insertineach
powerset [] = [[]]
powerset (x:xs) =
let
temp = powerset xs
in
(map (x:) temp) ++ temp
functions curry and uncurry
Curried form in ML
val ourimplode = foldr (op ^) "" o (map str);
(* notice something peculiar about foldr and map *)
fun pow 0 _ = 1
 pow 1 b = b
 pow _ 0 = 0
 pow e b = b * pow (e1) b;
(*
int * int > int
=>
int > int > int
*)
val square = pow 2;
val cube = pow 3;
map, foldl, are foldr are defined in
curried form (e.g., see definition of ourimplode above)
see [EMLP] Chapter 5 and, specifically §5.5 (pp. 168173),
for more information.
Variablelength argument lists in Scheme
Arguments to any function are always passed in as list.
It is up to the programmer to decompose that argument list
and group individual arguments
in the formal parameter specification of the function definition
using dot notation, if necessary.
(define f (lambda (x) x))
(f 1)
(f '(1 2 3))
;;; x is just the list (1 2 3)
(define f (lambda x x))
(f 1 2 3)
(f 1)
;;; uses pattern matching like ML and Haskell
;;; g and h take a variable number of arguments
(define g (lambda (x . y) x))
(define h (lambda (x . xs) xs))
;;; only 1 argument passed
(g '(1 2 3))
(h '(1 2 3))
(write "a")
(newline)
;;; now 2 arguments passed
(g 1 '(2 3))
(h 1 '(2 3))
;;; now 3 arguments passed
(g 1 2 3)
(h 1 2 3)
Currying in Scheme
 any language with firstclass closures can be used to define
functions in curried form
 first attempt:
;;; this is called `partial argument application'
;;; this example of currying is too tightly woven
;;; to the function being specialized
;;; moreover, pow now cannot be completely evaluated
(define pow
(lambda (e)
(cond
((eqv? e 0) 1)
(else
;; return a closure
(lambda (b)
(cond
((eqv? b 0) 0)
((eqv? b 1) 1)
((eqv? e 1) b)
(else (* b ((pow ( e 1)) b)))))))))
> (define square (pow 2))
> (square 4)
16
 second attempt:
(define s11
(lambda (f x)
(list 'lambda '(y) (list f x 'y))))
(define pow
(lambda (e b)
(cond
((eqv? b 0) 0)
((eqv? b 1) 1)
((eqv? e 0) 1)
((eqv? e 1) b)
(else (* b (pow ( e 1) b))))))
> (define square (s11 pow 2))
> square
(lambda (y) (#<procedure:pow> 2 y))
> (eval square)
#<procedure>
> ((eval square) 4)
16
 a similar approach:
;;; this is called `generalized explicit currying'
;;; notice we must explicitly call curry which, in turn,
;;; means we must know apriori how many arguments are contained
;;; in the complete argument list of the curried function
;;; however, this approach obviates the need explicitly to call eval and
;;; the need define multiple versions of s (e.g., to curry a 3 argument
;;; function in all ways possible would require s111, s12, and s21).
(define curry
(lambda (fun . args)
(lambda x
(apply fun (append args x)))))
(define square (curry pow 2))
> (square 4)
16
;; examples courtesy Jeffrey A. Meunier's article `Function Currying in Scheme'
;; and we can continue to currying the result as we desire
(define list1 (curry list 'A))
(define list2 (curry list1 'tree))
(define list3 (curry list2 'grows))
(list3 'in 'Brooklyn.)
;; since the original function of the curried function (which is list)
;; can accept multiple arguments,
;; the curried function can also accept multiple arguments
(define list4 (curry list 'A 'tree 'grows))
(list4 'in 'Brooklyn.)
 see Jeffrey A. Meunier's article
Function
Currying in Scheme for the details of implicit
currying
Partial evaluation
Generalizes the idea of currying from any prefix of the
argument list to any subset of the argument list.
Formally, states that for any function
f(x_{1}, x_{2}, ..., x_{n}),
f(a, b, ..., r)
=
g({x_{1}, x_{2}, ..., x_{n}}  {a, b, ..., r}),
where
{a, b, ..., r} ⊆
{x_{1}, x_{2}, ..., x_{n}},
such that
g(s, t, ..., z) =
f(a, b, ..., z).
References
[COPL6] 
R.W. Sebesta.
Concepts of Programming Languages.
AddisonWesley, Boston, MA, Sixth edition, 2003. 
[COPL9] 
R.W. Sebesta.
Concepts of Programming Languages.
AddisonWesley, Boston, MA, Ninth edition, 2010. 
[EMLP] 
J.D. Ullman.
Elements of ML Programming.
Prentice Hall, Upper Saddle River, NJ, Second edition, 1997. 
[PIH] 
G. Hutton.
Programming in Haskell.
Cambridge University Press, Cambridge, 2007.

[PLPP] 
K.C. Louden.
Programming Languages: Principles and Practice.
Brooks/Cole, Pacific Grove, CA, Second edition, 2002.

[SICP] 
H. Abelson and G.J. Sussman.
Structure and Interpretation of Computer Programs.
MIT Press, Cambridge, MA,
Second edition, 1996.

