From 93e78f6066b4b7bb212523c76016954ca8043a1d Mon Sep 17 00:00:00 2001 From: Jacob Signorovitch Date: Tue, 7 Oct 2025 19:49:43 -0400 Subject: [PATCH] Added Typed Racket. WTF this language actually sucks. --- .../main.rkt | 0 .../main.rkt | 0 .../main.rkt~ | 0 02-trees/main.rkt | 116 ++++++++++++++++++ trees/main.rkt => 02-trees/main.rkt~ | 0 03-higher-order-functions/main.rkt | 66 ++++++++++ 03-higher-order-functions/main.rkt~ | 22 ++++ 04-typed-racket/main.rkt | 44 +++++++ 8 files changed, 248 insertions(+) rename {welcome-back-to-dr-racket => 00-welcome-back-to-dr-racket}/main.rkt (100%) rename {list-and-let-list => 01-list-and-let-list}/main.rkt (100%) rename {list-and-let-list => 01-list-and-let-list}/main.rkt~ (100%) create mode 100644 02-trees/main.rkt rename trees/main.rkt => 02-trees/main.rkt~ (100%) create mode 100644 03-higher-order-functions/main.rkt create mode 100644 03-higher-order-functions/main.rkt~ create mode 100644 04-typed-racket/main.rkt diff --git a/welcome-back-to-dr-racket/main.rkt b/00-welcome-back-to-dr-racket/main.rkt similarity index 100% rename from welcome-back-to-dr-racket/main.rkt rename to 00-welcome-back-to-dr-racket/main.rkt diff --git a/list-and-let-list/main.rkt b/01-list-and-let-list/main.rkt similarity index 100% rename from list-and-let-list/main.rkt rename to 01-list-and-let-list/main.rkt diff --git a/list-and-let-list/main.rkt~ b/01-list-and-let-list/main.rkt~ similarity index 100% rename from list-and-let-list/main.rkt~ rename to 01-list-and-let-list/main.rkt~ diff --git a/02-trees/main.rkt b/02-trees/main.rkt new file mode 100644 index 0000000..52ef480 --- /dev/null +++ b/02-trees/main.rkt @@ -0,0 +1,116 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-intermediate-reader.ss" "lang")((modname main) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) +; A MaybeTree is one of +; - (make-tree [Number MaybeTree MaybeTree]) +(define-struct tree [n left right]) +; - 'end + +(define sprout (make-tree 0 'end 'end)) +(define seedling (make-tree 5 sprout (make-tree 6 'end 'end))) +(define sapling (make-tree 10 + (make-tree 6 sprout 'end) + (make-tree 12 'end 'end))) +(define good-tree (make-tree 50 sapling (make-tree 100 'end 'end))) +(define broke-tree (make-tree 5 good-tree good-tree)) +(define deeply-broke-tree (make-tree 5 (make-tree 3 (make-tree 2 sprout sprout) 'end) (make-tree 10 (make-tree 7 'end 'end) 'end))) + +; Tree t -> Bool +; Determines whether a Tree is a binary search tree. +(define (bst? t) + (local [; Tree t -> Bool + ; Recursively checks left and right. + (define (recurse t) + (or (and (symbol? t) (symbol=? t 'end)) + (and (acc-right (tree-right t) (tree-n t)) + (acc-left (tree-left t) (tree-n t))))) + + ; Tree t, Number n -> Bool + ; Accumulates the current number to check left. + (define (acc-left t n) + (or (and (symbol? t) (symbol=? t 'end)) + (and (< (tree-n t) n) (recurse t)))) + + ; Tree t, Number n -> Bool + ; Accumulates the current number to check right. + (define (acc-right t n) + (or (and (symbol? t) (symbol=? t 'end)) + (and (> (tree-n t) n) (recurse t))))] + (recurse t))) + +(check-expect (bst? sprout) #t) +(check-expect (bst? sapling) #t) +(check-expect (bst? good-tree) #t) +(check-expect (bst? broke-tree) #f) +(check-expect (bst? deeply-broke-tree) #f) + +; A Trie is a [Node] + +; A Node is a +; (make-node [String c Boolean e [Node] l]) +; and represents a prefix tree. 'c' represents the node character, 'e' is a +; flag for if the node marks the end of a word in the tree, and 'l' is the list +; of child nodes. +(define-struct node [c e l]) + +(define example-trie + (list (make-node "a" #t + (list (make-node "n" #t (list (make-node "d" #t '()) (make-node "t" #t '()))))) + (make-node "b" #f + (list (make-node "e" #t (list (make-node "e" #t '()) (make-node "t" #t (list (make-node "t" #f (list (make-node "e" #f (list (make-node "r" #t '()))))))))))) + (make-node "c" #f (list (make-node "a" #f (list (make-node "t" #t '()))))))) + +; String w, Trie t -> Boolean +; Determines whether the given word is in the given Trie. +(define (in-trie? w t) + (local [; [Node] l, String wsf -> Boolean + ; Basically ormap of in?h on list of nodes but no lambda so this exists. + (define (childs? l wsf) + (and (not (empty? l)) + (or (in?h (first l) wsf) (childs? (rest l) wsf)))) + + ; Node n, String wsf -> Boolean + ; Helper for in?. Accumulates word so far. + (define (in?h n wsf) + (or (and (string=? (string-append wsf (node-c n)) w) (node-e n)) (childs? (node-l n) (string-append wsf (node-c n))))) + + ; Node n -> Boolean + ; Determines whether word is in the node or child nodes. + (define (in? n) (in?h n ""))] (ormap in? t))) + +(check-expect (in-trie? "cat" example-trie) #t) +(check-expect (in-trie? "ca" example-trie) #f) +(check-expect (in-trie? "catch" example-trie) #f) +(check-expect (in-trie? "better" example-trie) #t) +(check-expect (in-trie? "bee" example-trie) #t) +(check-expect (in-trie? "beee" example-trie) #f) + +; [String] l -> Trie +; Generates the trie for a list of strings. +(define (strie l) + (local [; String w, Trie t -> Trie + ; Adds word w to a Trie. + (define (triadd w t) + (local [; String c, String wrest, Trie t -> Trie + ; Helper function to insert a chacater (and the rest of the word) to the Trie. + (define (insert-char c wrest t) + (cond [(empty? t) + (list (make-node c ; Node character. + (string=? wrest "") ; Mark whether Node's a word end. + (if (string=? wrest "") ; If more left in the word, recurse. + '() + (triadd wrest '()))))] + [(string=? (node-c (first t)) c) ; Character matches -- return existing Trie Node + whatever added if necessary. + (cons (make-node c + (or (node-e (first t)) + (string=? wrest "")) + (if (string=? wrest "") + (node-l (first t)) + (triadd wrest (node-l (first t))))) ; Recurse. + (rest t))] + [else + (cons (first t) (insert-char c wrest (rest t)))]))] + (insert-char (substring w 0 1) (substring w 1) t)))] + (foldl triadd '() l))) + +(check-expect (strie '("and" "bee" "cat" "an" "a" "ant" "better" "bet" "be")) example-trie) diff --git a/trees/main.rkt b/02-trees/main.rkt~ similarity index 100% rename from trees/main.rkt rename to 02-trees/main.rkt~ diff --git a/03-higher-order-functions/main.rkt b/03-higher-order-functions/main.rkt new file mode 100644 index 0000000..0f0aaf6 --- /dev/null +++ b/03-higher-order-functions/main.rkt @@ -0,0 +1,66 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname main) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) +; foo: bar: (A → A) → (A → A) +(define (foo bar) + (local [(define (baz buzz) + (bar (bar buzz)))] baz)) + +(check-expect ((foo add1) 1) 3) + +; goodies: good?: (A → Boolean), l: [A] → [Index] +; Returns a list of indices considered "good." +(define (goodies good? l) + (local [; goodies/help: l: [A], i: Index, a: [Index] → [Index] + (define (goodies/help l i a) + (cond [(empty? l) (reverse a)] + [(good? (first l)) (goodies/help (rest l) (add1 i) (cons i a))] + [else (goodies/help (rest l) (add1 i) a)]))] + (goodies/help l 0 '()))) + +(check-expect (goodies even? '(1 2 3 4 5)) '(1 3)) +(check-expect (goodies even? '()) '()) + +; groupby: key: (A → B), l: [A], same? (B, B → Boolean) → [[A]] +; This isn't tail-recursive, so it takes up more memory than strictly necessary, but it doesn't need to reverse the list so probably faster. +(define (groupby key l same?) + (if (empty? l) '() + (local [(define key1same? (λ (x) (same? (key x) (key (first l)))))] + (cons (filter key1same? l) (groupby key (filter (λ (x) (not (key1same? x))) l) same?))))) + +(check-expect (groupby even? '(1 2 3 4 5) equal?) '((1 3 5) (2 4))) +(check-expect (groupby (lambda (x) (modulo x 3)) '(1 2 1 2 54 2 5 43 7 2 643 1 2 0) equal?) '((1 1 43 7 643 1) (2 2 2 5 2 2) (54 0))) + +; cart: [[A]] → [[A]] +; Takes a list of n lists, and computes the n-ary cartesian product. +(define (cart ll) + (foldr (λ (l acc) + (foldr append ; Concat all lists. + '() + (map (λ (x) (map (λ (m) (cons x m)) acc)) l))) ; Create list of lists for each x. + '(()) ; Base case. + ll)) + +(check-expect (cart '((1 2 3) (a b c))) + '((1 a) (1 b) (1 c) (2 a) (2 b) (2 c) (3 a) (3 b) (3 c))) +(check-expect (cart '((4 5 6) (d e f) (#t #f))) + '((4 d #t) + (4 d #f) + (4 e #t) + (4 e #f) + (4 f #t) + (4 f #f) + (5 d #t) + (5 d #f) + (5 e #t) + (5 e #f) + (5 f #t) + (5 f #f) + (6 d #t) + (6 d #f) + (6 e #t) + (6 e #f) + (6 f #t) + (6 f #f))) + + \ No newline at end of file diff --git a/03-higher-order-functions/main.rkt~ b/03-higher-order-functions/main.rkt~ new file mode 100644 index 0000000..da98fe5 --- /dev/null +++ b/03-higher-order-functions/main.rkt~ @@ -0,0 +1,22 @@ +;; The first three lines of this file were inserted by DrRacket. They record metadata +;; about the language level of this file in a form that our tools can easily process. +#reader(lib "htdp-intermediate-lambda-reader.ss" "lang")((modname main) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) +; foo: (bar: A → A) → (A → A) +(define (foo bar) + (local [(define (baz buzz) + (bar (bar buzz)))] baz)) + +(check-expect ((foo add1) 1) 3) + +; goodies: (good?: A → Boolean, l: [A]) → [Index] +; Returns a list of indices considered "good." +(define (goodies good? l) + (local [; goodies/help: (good?: A → Boolean, l :[A], i: Int, a: [Index]) → [Index] + (define (goodies/help l i a) + (cond [(empty? l) (reverse a)] + [(good? (first l)) (goodies/help (rest l) (add1 i) (cons i a))] + [else (goodies/help (rest l) (add1 i) a)]))] + (goodies/help l 0 '()))) + +(check-expect (goodies even? '(1 2 3 4 5)) '(1 3)) +(check-expect (goodies even? '()) '()) diff --git a/04-typed-racket/main.rkt b/04-typed-racket/main.rkt new file mode 100644 index 0000000..b2cfb91 --- /dev/null +++ b/04-typed-racket/main.rkt @@ -0,0 +1,44 @@ +#lang pl + +; I'm keeping my own type declarations bc the racket ones are literally unreadable. +; gcd2: a: Int, b: Int → Int +(: gcd2 : (Integer Integer -> Integer)) +; Given two non-negative integers, determine their greatest common divisor. +(define (gcd2 a b) + (cond + [(or (negative? a) (negative? b)) (error 'neg "Given negative number.")] + [(= a 0) b] + [(= b 0) a] + [(and (even? a) (even? b)) (* 2 (gcd2 (floor (/ a 2)) (floor (/ b 2))))] + [(even? b) (gcd2 a (floor (/ b 2)))] + [(even? a) (gcd2 (floor (/ a 2)) b)] + [else + (if (<= a b) + (gcd2 a (- b a)) + (gcd2 b (- a b)))])) + +(test (gcd2 0 0) => 0) +(test (gcd2 288 64) => 32) +; What's the point of the symbol in the error definition if it isn't used to check errors? +(test (gcd2 2 -1) =error> "Given negative number.") + +; out-of-bounds?: start: Number, +; lower: Number, +; upper: Number, +; l: [Number] → Bool +(: out-of-bounds? : (Number Number Number (Listof Number) -> Boolean)) +; Determines if an object that begins at the starting location and then moves delta by delta ever ever steps outside of the bounds (inclusive). +(define (out-of-bounds? start lower upper l) + (if (or (< start lower) (> start upper)) + #t + (match l + ['() #f] + [(cons frst rst) (out-of-bounds? frst lower upper rst)]))) + +(test (out-of-bounds? 0 -1 2 '(0 -2 3 -4 6)) => #t) +(test (out-of-bounds? 0 -1 1 '(1)) => #f) +(test (out-of-bounds? 0 -1 1 '()) => #f) +(test (out-of-bounds? 0 1 2 '()) => #t) +(test (out-of-bounds? 0 0 0 '()) => #f) + +