diff --git a/HW1.fsx b/HW1.fsx new file mode 100644 index 0000000..5c1f778 --- /dev/null +++ b/HW1.fsx @@ -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];; diff --git a/HW2.fsx b/HW2.fsx new file mode 100644 index 0000000..bbb5bbe --- /dev/null +++ b/HW2.fsx @@ -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) + +/// 3. Transpose an m-by-n matrix +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 +*) +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 +*) diff --git a/HW3.fsx b/HW3.fsx new file mode 100644 index 0000000..18f62ec --- /dev/null +++ b/HW3.fsx @@ -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)