Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions HW1.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
(*
Jose Gabriel Perez
ex 1: could save gcd on reduce to avoid double calc on big nums
Also, finding common denom instead to reduce computing could be better for large numbers
*)

//ex1
let rec gcd = function
| (a,0) -> a
| (a,b) -> gcd (b, a % b)

let reduce = function
| (a, b) -> (a/gcd(a,b), b/gcd(a,b))

let (.+) (a,b) (c,d) = reduce (a*d + b*c, b*d)
let (.*) (a,b) (c,d) = reduce (a*c, b*d)

//ex2
let revlists l = List.map List.rev l

//ex3 Really banking on l1 and l2 having equal length, otherwise it will just do it up to the smaller size
let rec interleave = function
| ([], l) -> []
| (l, []) -> []
| (x::xs, y::ys) -> x:: y :: interleave(xs, ys)

//ex4
let gencut(n, l1) =
let rec helpcut (n, a, b) =
if List.isEmpty b then (n, a, b)
elif List.length a < n then helpcut (n, a @ (List.head b :: []), List.tail b)
else (n, a, b)
let (_, f1, f2) = helpcut (n, [], l1)
(f1, f2)

let cut l1 = gencut((List.length l1)/2, l1)

//ex5
let shuffle l = interleave (cut l)

//ex6
let countshuffles n =
let rec countaux(deck, target) =
if deck = target then 0
else 1 + countaux(shuffle deck, target)
countaux(shuffle [1..n],[1..n]) + 1

//samples
interleave ([1;2;3],[4;5;6]);;
cut [1;2;3;4;5;6];;
shuffle [1;2;3;4];;
countshuffles 8;;
countshuffles 52;;

shuffle [1; 2; 3; 4; 5; 6; 7; 8];;
shuffle [1; 5; 2; 6; 3; 7; 4; 8];;
shuffle [1; 3; 5; 7; 2; 4; 6; 8];;
74 changes: 74 additions & 0 deletions HW2.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
(* Homework 2

*)

/// 1. Returns a list of pairs that represents the cartesian product
let rec cartesian(xs, ys) =
match xs, ys with
| (xs, []) -> []
| ([], ys) -> []
| (x::xs, ys) -> (List.map(fun y -> x,y) ys) @ (cartesian (xs,ys));;

/// 2. Powerset set returns the set of all subsets of set
let rec powerset = function
| [] -> [[]]
| x::xs -> List.collect (fun subset -> [subset; x::subset]) (powerset xs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kill the indents

let rec powerset = function
| [] -> [[]]
| x::xs -> List.collect (fun subset -> [subset; x::subset]) (powerset xs)


/// 3. Transpose an m-by-n matrix
let rec transpose = function
| (_::_)::_ as M -> List.map List.head M :: transpose (List.map List.tail M)
| _ -> []
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

let rec transpose = function
| (_::_)::_ as M -> List.map List.head M :: transpose (List.map List.tail M)
| _ -> []


//// 4. Correctness of sort recursive function with respect to the Checklist for Programming with Recursion
(*
Step One: It is okay, because empty and single item lists are automatically sorted
Step Two: wrong, because even assuming that sort (x2::xs) returns the correct answer, there is no guarantee
that x1 is the minimun since it was only compared to x2 and is not checked again.
For a counter example sort [3;2;1];; will return [2;1;3;].
All that this sort function really guarantees is that the largest element goes to the end of the list.
(Note: works like the insertion step of insertion sort, if it gets called n-1 times the list would be sorted)
Step Three: Each recursive call gets an input that is smaller than the original input
*)
let rec sort = function
| [] -> []
| [x] -> [x]
| x1::x2::xs -> if x1 <= x2 then x1 :: sort (x2::xs)
else x2 :: sort (x1::xs)

/// 5. Analyze mergesort with respect to the Checking for Programming with Recursion (merge and split work correctly)
(*
Step One: It is okay, because empty lists are automatically sorted
Step Two: If mergesort of M and N return the correct answer, then since split and merge are correct the non-base case
is correct too. There is a missing base case that leads to a bug, but step 2 is still satisfied.
Step Three: Each recursive call gets an input that is smaller than the original input

Clue something is wrong: The mergesort function is missing a case, which causes mergesort to be seen by
the compiler as 'a list -> 'b list instead of 'a list -> 'a list
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... list instead of 'a list -> 'a list which tells us our merge sort is returning a list of items of a different type than given, which shouldn't be the case as we're simply sorting the elements.

*)
let rec merge = function
| ([], ys) -> ys
| (xs, []) -> xs
| (x::xs, y::ys) -> if x < y then x :: merge (xs, y::ys)
else y :: merge (x::xs, ys)

let rec split = function
| [] -> ([], [])
| [a] -> ([a], [])
| a::b::cs -> let (M,N) = split cs
(a::M, b::N)

let rec mergesort = function
| [] -> []
| [x] -> [x] //Bug corrected
| L -> let (M, N) = split L
merge (mergesort M, mergesort N)

/// 6. Define F# function curry f that converts an uncurried function to a curried function, and
(* an F# uncurry f that does the opposite conversion *)
let curry f a b = f (a, b)
let uncurry f (a,b) = f a b

(*
val curry : ('a * 'b -> 'c) -> 'a -> 'b -> 'c
val uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'c
*)
81 changes: 81 additions & 0 deletions HW3.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 1
let rec inner xs ys =
match (xs, ys) with
| ([x],[y]) -> x*y
| (x::xs, y::ys) -> x*y + inner xs ys
| (_, _)-> failwith "inner defined for equal sized lists only"



// 2 using transpose from last HW
let rec transpose = function
| (_::_)::_ as M -> List.map List.head M :: transpose (List.map List.tail M)
| _ -> []

// Posible to improve this by transposing beforehand
let rec multiply = function
|([], _) -> []
|(x::xs, ys) -> List.map (inner x) (transpose ys) :: multiply (xs, ys)

// 3
let flatten1 xs = List.fold (@) [] xs
let flatten2 xs = List.foldBack (@) xs []
let makelistlist n = List.map (fun x -> [x]) [1..n]
#time
(*In practice flatten1 behaves as O(n^2) and flatten2 is (O(n))*)

// 4
(*
twice successor 0 would be 2 = 2^1
twice twice successor 0 would be 4 = 2^2
twice twice twice successor 0 would be 16 = 2^4
And so on..

The current value becomes equals to 2 to the power of the previous value

The function will be defined recursively, as follows:
f(n) =
if n = 0 then 1
else 2 ^ (f(n-1))

We can write this function as:
let rec f = function
| 0 -> 1.0
| n -> 2.0 ** (f (n-1));;
*)

// 5
type 'a stream = Cons of 'a * (unit -> 'a stream);;

let rec map f (Cons(x, xsf)) = Cons (f x, fun() -> map f (xsf()));;

// 6
type Exp = Num of int
| Neg of Exp
| Sum of Exp * Exp
| Diff of Exp * Exp
| Prod of Exp * Exp
| Quot of Exp * Exp

let rec evaluate = function
| Num n -> Some n
| Neg e -> match evaluate e with
| None -> None
| Some n -> Some (-1 * n)
|Sum (e1, e2) -> match (evaluate e1, evaluate e2) with
|(None, _) -> None
|(_, None) -> None
|(Some n1, Some n2) -> Some (n1 + n2)
|Diff (e1, e2) -> match (evaluate e1, evaluate e2) with
|(None, _) -> None
|(_, None) -> None
|(Some n1, Some n2) -> Some (n1 - n2)
|Prod (e1, e2) -> match (evaluate e1, evaluate e2) with
|(None, _) -> None
|(_, None) -> None
|(Some n1, Some n2) -> Some (n1 * n2)
|Quot (e1, e2) -> match (evaluate e1, evaluate e2) with
|(None, _) -> None
|(_, None) -> None
|(_, Some 0) -> None
|(Some n1, Some n2) -> Some (n1 - n2)