Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
CSE 341 22sp
CSE 341 22sp public
Commits
43f079a5
Commit
43f079a5
authored
May 09, 2022
by
James R. Wilcox
Browse files
code from friday
parent
30b634fb
Changes
2
Hide whitespace changes
Inline
Sidebyside
lecture/L18/lec18.ml
0 → 100644
View file @
43f079a5
(* Curried filter *)
let
rec
filter
f
=
(
fun
xs
>
match
xs
with

[]
>
[]

x
::
xs'
>
if
f
x
then
x
::
((
filter
f
)
xs'
)
else
((
filter
f
)
xs'
))
let
greater_than
x
=
fun
y
>
x
<
y
let
is_positive
=
greater_than
0
let
contains_only_positives
=
filter
is_positive
let
all_greater
(
xs
,
n
)
=
(
filter
(
greater_than
n
))
xs
let
rec
sum
xs
=
match
xs
with

[]
>
0

x
::
xs
>
x
+
sum
xs
let
all_whose_sum_is_greater_than_sum
(
xss
,
ys
)
=
(
filter
(
fun
xs
>
sum
xs
>
sum
ys
))
xss
(* why is this potentially faster? *)
let
all_whose_sum_is_greater_than_sum'
(
xss
,
ys
)
=
let
n
=
sum
ys
in
(
filter
(
fun
xs
>
sum
xs
>
n
))
xss
(* another hall of fame function *)
let
rec
fold_left
(
f
,
acc
,
xs
)
=
match
xs
with

[]
>
acc

x
::
xs'
>
fold_left
(
f
,
(
f
(
acc
,
x
))
,
xs'
)
(* examples that do not capture private data *)
let
sum
xs
=
fold_left
((
fun
(
acc
,
x
)
>
acc
+
x
)
,
0
,
xs
)
let
contains_only_positives
xs
=
fold_left
((
fun
(
acc
,
x
)
>
acc
&&
x
>=
0
)
,
true
,
xs
)
(* examples that *do* capture private data *)
let
count_in_range
(
lo
,
hi
,
xs
)
=
fold_left
((
fun
(
acc
,
x
)
>
acc
+
(
if
lo
<=
x
&&
x
<
hi
then
1
else
0
))
,
0
,
xs
)
let
are_all_sums_greater_than
(
xss
,
ys
)
=
let
n
=
sum
ys
in
fold_left
((
fun
(
acc
,
xs
)
>
acc
&&
sum
xs
>
n
)
,
true
,
xss
)
let
for_all
(
f
,
xs
)
=
fold_left
((
fun
(
acc
,
x
)
>
acc
&&
f
x
)
,
true
,
xs
)
let
contains_only_positives'
xs
=
for_all
((
fun
x
>
x
>
0
)
,
xs
)
let
are_all_sums_greater_than'
(
xss
,
ys
)
=
let
n
=
sum
ys
in
for_all
((
fun
xs
>
sum
xs
>
n
)
,
xss
)
(* Currying *)
let
sorted3_tuple
(
x
,
y
,
z
)
=
x
<=
y
&&
y
<=
z
let
_
=
sorted3_tuple
(
7
,
9
,
11
)
let
sorted3
=
fun
x
>
(
fun
y
>
(
fun
z
>
x
<=
y
&&
y
<=
z
))
let
_
=
((
sorted3
7
)
9
)
11
let
_
=
sorted3
7
9
11
let
sorted3_spaces_fun
=
fun
x
y
z
>
x
<=
y
&&
y
<=
z
let
_
=
sorted3_spaces_fun
7
9
11
let
sorted3_spaces
x
y
z
=
x
<=
y
&&
y
<=
z
let
_
=
sorted3_spaces
7
9
11
let
is_positive
=
sorted3_spaces
0
0
(* fold again, but now curried *)
(* this exact definition is in the stdlib at List.fold_left *)
let
rec
fold_left
f
acc
xs
=
match
xs
with

[]
>
acc

x
::
xs'
>
fold_left
f
(
f
acc
x
)
xs'
let
sum_meh_style
xs
=
(
fold_left
(
fun
acc
x
>
acc
+
x
)
0
)
xs
let
sum_good_style
=
fold_left
(
fun
acc
x
>
acc
+
x
)
0
let
remove_negs_meh
xs
=
List
.
filter
(
fun
x
>
x
>=
0
)
xs
(* partial application and currying allows us to use "variablestyle" let *)
let
remove_negs
=
List
.
filter
(
fun
x
>
x
>=
0
)
let
remove_all
n
=
List
.
filter
(
fun
x
>
x
<>
n
)
let
remove_zeros
=
remove_all
0
let
increment_all
=
List
.
map
(
fun
x
>
x
+
1
)
(* in the library as List.exists *)
let
rec
exists
p
xs
=
match
xs
with

[]
>
false

x
::
xs'
>
p
x

exists
p
xs'
let
exists
p
xs
=
List
.
fold_left
(
fun
acc
x
>
acc

p
x
)
false
xs
let
exists
p
=
List
.
fold_left
(
fun
acc
x
>
acc

p
x
)
false
(* in the library as List.for_all *)
let
for_all
p
=
List
.
fold_left
(
fun
acc
x
>
acc
&&
p
x
)
true
let
has_zero
=
exists
(
fun
x
>
x
=
0
)
let
no_zeros
=
for_all
(
fun
x
>
x
<>
0
)
(* currying is the norm in OCaml, even if partial application is unlikely *)
let
rec
append
xs
ys
=
match
xs
with

[]
>
ys

x
::
xs'
>
x
::
append
xs'
ys
(******** value restriction *********)
let
remove_empty_lists
xs
=
List
.
filter
(
fun
x
>
List
.
length
x
>
0
)
xs
(* look at the type, it's not 'a list list > 'a list list as we would expect *)
let
_
=
remove_empty_lists
[[];
[
true
]]
(* *now* look at the type!! *)
let
_
=
remove_empty_lists
[[];
[
1
]]
(* oh no  that didn't work! *)
(* workaround if you want polymorphics: go back to "bad" style :\ *)
let
remove_empty_lists
xs
=
List
.
filter
(
fun
x
>
List
.
length
x
>
0
)
xs
let
_
=
remove_empty_lists
[[];
[
1
]]
let
_
=
remove_empty_lists
[[];
[
true
]]
(* next idiom: combining functions *)
(* function composition (righttoleft, like math) *)
let
compose
=
fun
f
>
fun
g
>
(
fun
x
>
f
(
g
x
))
let
compose_shorter
f
g
x
=
f
(
g
x
)
(* infix notation for composition *)
let
(
%
)
=
compose
(* unnecessary function wrapping again here: *)
let
double_plus_one
x
=
compose
(
fun
x
>
x
+
1
)
(
fun
x
>
2
*
x
)
x
let
_
=
double_plus_one
3
(* "variablestyle" let binding is better style *)
let
double_plus_one
=
compose
(
fun
x
>
x
+
1
)
(
fun
x
>
2
*
x
)
let
_
=
double_plus_one
3
(* also nice to use the infix operator *)
let
double_plus_one
=
(
fun
x
>
x
+
1
)
%
(
fun
x
>
2
*
x
)
let
_
=
double_plus_one
3
let
sqrt_of_abs
i
=
Float
.
sqrt
(
float_of_int
(
Int
.
abs
i
))
let
sqrt_of_abs
i
=
(
Float
.
sqrt
%
float_of_int
%
Int
.
abs
)
i
let
sqrt_of_abs
=
Float
.
sqrt
%
float_of_int
%
Int
.
abs
let
_
=
sqrt_of_abs
(

8
)
(* pipeline operator (lefttoright) *)
(* actually builtin to OCaml, but here's the definition *)
let
(
>
)
x
f
=
f
x
let
sqrt_of_abs
i
=
i
>
Int
.
abs
>
float_of_int
>
Float
.
sqrt
let
_
=
sqrt_of_abs
(

8
)
(* also lefttoright *)
let
pipeline_option
f
g
=
fun
x
>
match
f
x
with

None
>
None

Some
y
>
g
y
let
sqrt_if_positive
=
pipeline_option
(
fun
i
>
if
i
>
0
then
Some
(
float_of_int
i
)
else
None
)
((
fun
x
>
Some
x
)
%
sqrt
)
let
_
=
sqrt_if_positive
3
let
_
=
sqrt_if_positive
(

3
)
(* converting between curried and tupled versions of a function *)
let
curried_of_paired
f
x
y
=
f
(
x
,
y
)
let
paired_of_curried
f
(
x
,
y
)
=
f
x
y
(* more verbose but less "tricky" versions of the above: *)
(*
let curried_of_paired f = fun x > fun y > f (x, y)
let paired_of_curried f = fun (x, y) > (f x) y
*)
(* check out how much the types tell us above and here: *)
let
swap_tupled
f
(
x
,
y
)
=
f
(
y
,
x
)
let
swap_curried
f
x
y
=
f
y
x
let
rec
range
(
lo
,
hi
)
=
if
lo
>
hi
then
[]
else
lo
::
range
(
lo
+
1
,
hi
)
(* no problem using range as curried even though it's tupled 
convert it
*)
let
countup
=
(
curried_of_paired
range
)
0
let
_
=
countup
5
(*  *)
(* refs and mutable state *)
let
x
=
ref
42
let
y
=
ref
42
let
z
=
x
let
_
=
x
:=
43
let
w
=
!
x
+
!
z
(* does not typecheck: *)
(* let _ = x + 1 *)
(*  *)
(* callback library *)
let
callbacks
:
(
int
>
unit
)
list
ref
=
ref
[]
let
on_key_event
f
=
(* only library binding that clients should use *)
callbacks
:=
f
::
!
callbacks
let
rec
iter
f
xs
=
(* like map, but produces no data. (In the library as List.iter.) *)
match
xs
with

[]
>
()

x
::
xs'
>
let
_
=
f
x
in
iter
f
xs'
let
do_key_event
i
=
List
.
iter
(
fun
f
>
f
i
)
!
callbacks
(* end of callback library implementation *)
(* callback client *)
let
times_pressed
=
ref
0
(* actually builtin, but here's the definition *)
let
incr
int_ref
=
int_ref
:=
!
int_ref
+
1
let
()
=
on_key_event
(
fun
_
>
incr
times_pressed
)
let
_
=
!
times_pressed
(* callback has not been called yet *)
(* imagine these happened from "the outside world" *)
let
()
=
do_key_event
97
let
()
=
do_key_event
98
let
()
=
do_key_event
99
(* we can see our callback was called *)
let
_
=
!
times_pressed
let
print_if_pressed
i
=
on_key_event
(
fun
j
>
if
i
=
j
then
print_endline
(
"pressed "
^
string_of_int
i
)
else
()
)
let
()
=
do_key_event
97
let
()
=
print_if_pressed
122
let
()
=
do_key_event
98
let
()
=
do_key_event
122
let
_
=
!
times_pressed
(*  *)
(* ADTs via closures *)
type
set
=
S
of
{
insert
:
int
>
set
;
member
:
int
>
bool
;
size
:
unit
>
int
;
}
let
empty_set
=
let
rec
make_set
xs
=
(* xs is a "private field" in result *)
let
contains
i
=
List
.
mem
i
xs
in
(* contains is a "private method" *)
S
{
insert
=
(
fun
i
>
if
contains
i
then
make_set
xs
else
make_set
(
i
::
xs
));
member
=
contains
;
size
=
(
fun
()
>
List
.
length
xs
)
}
in
make_set
[]
(* client *)
let
_
=
let
S
s1
=
empty_set
in
let
S
s2
=
s1
.
insert
34
in
let
S
s3
=
s2
.
insert
34
in
let
S
s4
=
s3
.
insert
19
in
s4
.
size
()
lecture/L18/lec18live.ml
0 → 100644
View file @
43f079a5
let
x
=
1
(* why is lexical scope useful? *)
(* 3 reasons why lexical scope is better
 "alpha renaming" or "alpha equivalence": "variable names don't mattern"
 write the same program twice using different variable names,
as long I'm consistent within each version, the programs should be equivalent
 lexical scope supports type checking (or scope checking)
 can do local type checking
 allows closures to safely capture data they need to do their work
*)
let
f
x
=
(* we say this anonymous function "captures" x *)
fun
y
>
x
+
y
let
f2
z
=
fun
y
>
z
+
y
(* under dynamic scope, could get different answers*)
let
g
=
f
3
(* spec: g adds 3 to its argument *)
let
x
=
1
let
a
=
g
4
(* lexical scope: 7 *)
(* dynamic scope: 5 *)
(* "how to program with closures" *)
(* currying *)
let
rec
filter
(
f
,
xs
)
=
match
xs
with

[]
>
[]

x
::
xs
>
if
f
x
then
x
::
filter
(
f
,
xs
)
else
filter
(
f
,
xs
)
let
only_positive
xs
=
filter
((
fun
x
>
x
>
0
)
,
xs
)
(* List.filter *)
let
rec
filter
f
=
fun
xs
>
match
xs
with

[]
>
[]

x
::
xs
>
if
f
x
then
x
::
(
filter
f
)
xs
else
(
filter
f
)
xs
let
only_positive
xs
=
(
filter
(
fun
x
>
x
>
0
))
xs
let
only_positive
xs
=
filter
(
fun
x
>
x
>
0
)
xs
(* partial application  passing only some of the arguments, get back a function expecting rest *)
let
only_positive
=
(
filter
(
fun
x
>
x
>
0
))
let
only_positive
=
filter
(
fun
x
>
x
>
0
)
let
rec
filter
f
xs
=
match
xs
with

[]
>
[]

x
::
xs
>
if
f
x
then
x
::
filter
f
xs
else
filter
f
xs
let
rec
filter
=
fun
f
>
fun
xs
>
match
xs
with

[]
>
[]

x
::
xs
>
if
f
x
then
x
::
filter
f
xs
else
filter
f
xs
(* two abbreviations that support currying for all function definitions and calls:
 definitions
let f x y = ...
is shorthand for
let f = fun x > fun y > ...
 calls
f e1 e2
is shorthand for
(f e1) e2
*)
let
rec
sum
xs
=
match
xs
with

[]
>
0

x
::
xs
>
x
+
sum
xs
let
all_whose_sum_is_greather_than_sum
(
xss
,
ys
)
=
filter
(
fun
xs
>
sum
xs
>
sum
ys
)
xss
let
l
=
[[
1
;
2
;
3
];
[
4
;
5
;
6
]]
let
l2
=
all_whose_sum_is_greather_than_sum
(
l
,
[
4
;
5
])
let
all_whose_sum_is_greather_than_sum'
(
xss
,
ys
)
=
let
n
=
sum
ys
in
filter
(
fun
xs
>
sum
xs
>
n
)
xss
let
all_whose_sum_is_greather_than_sum'
(
xss
,
ys
)
=
filter
(
fun
xs
>
let
n
=
sum
ys
in
sum
xs
>
n
)
xss
(* another hall of fame function *)
let
rec
fold_left
f
acc
xs
=
match
xs
with

[]
>
acc

x
::
xs'
>
fold_left
f
(
f
acc
x
)
xs'
let
sum_via_fold
xs
=
fold_left
(
fun
acc
x
>
acc
+
x
)
0
xs
let
sum_via_fold
=
fold_left
(
fun
acc
x
>
acc
+
x
)
0
let
count_in_range
lo
hi
=
(* in the anonymous function below, "lo" and "hi" come from the outer environment *)
fold_left
(
fun
acc
x
>
if
lo
<=
x
&&
x
<
hi
then
1
+
acc
else
acc
)
0
(* "use a variablestyle let binding, not a functionstyle let binding "*)
let
rec
append
xs
ys
=
match
xs
with

[]
>
ys

x
::
xs'
>
x
::
append
xs'
ys
let
f
=
append
[
1
;
2
;
3
]
(* f takes a list of integers and appends [1; 2; 3] to the beginning *)
(* the VALUE RESTRICTION *)
let
remove_empty_lists
xss
=
List
.
filter
(
fun
xs
>
List
.
length
xs
>
0
)
xss
let
remove_empty_lists
=
fun
xss
>
List
.
filter
(
fun
xs
>
List
.
length
xs
>
0
)
xss
let
remove_empty_lists2
=
List
.
filter
(
fun
xs
>
List
.
length
xs
>
0
)
(* fix by reintroducing "unnecessary" (actually necessary) function wrapping *)
let
remove_empty_lists2
xss
=
List
.
filter
(
fun
xs
>
List
.
length
xs
>
0
)
xss
(* converting back and forth between tupled and curried multiarg functions *)
let
convert_from_tupled_to_curried
f
=
fun
x
>
fun
y
>
f
(
x
,
y
)
(* val convert_from_tupled_to_curried : ('a * 'b > 'c) > 'a > 'b > 'c = <fun> *)
(* remember this is equivalent to parentheses: *)
(* val convert_from_tupled_to_curried : ('a * 'b > 'c) > ('a > 'b > 'c) = <fun> *)
let
curry
f
=
fun
x
>
fun
y
>
f
(
x
,
y
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment