aboutsummaryrefslogtreecommitdiff
path: root/sem7/pp/lec1/exercises.scm
blob: 622098261c6c0f17f12ed56bd9f9b48d049fa55b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
(define (make-list-ft from to)
  (if (> from to)
      '()
      (cons from (make-list-ft (1+ from) to))))

;;# Exercise 1.3 (proper lists)
;;? Program own version of list?, thus proper-list?
;; This is done by running to the end of list, always checking if pair.
;; If last element is '() its a proper list, otherwize its not.
(define (proper-list? list)
  (if (pair? list)
      (proper-list? (cdr list))
      (null? list)))

;;? Can you write your predicate without using if or cond?
;; Hmm i cant see how this would be done, as we are using recursion which requires a stop condition.
;; Hmm reading through the solution, i see that we can use other conditional functions like `or` and `and`.
;; Lets try that
(define (proper-list? list)
  (or (null? list) (and (pair? list) (proper-list? (cdr list)))))

;;? Is your function efficient? What is the time complexity?
;; This runs over all the elements in the list, so O(n).

;; Okay thats just his solution

;;# Exercise 1.5 (every second element)
;; Hmm the text mentions that we could write it with (every-nth-element)
(define (every-nth-element n list)
  (let recur ((list list) (index 0))
    (cond ((null? list) '())
	  ((zero? (modulo index n)) (cons (car list) (recur (cdr list) (1+ index))))
	  (else (recur (cdr list) (1+ index))))))

;; With letrec
(define (every-nth-element n list)
  (letrec ([recur (lambda (list index)
		    (cond [(null? list) '()]
			  [(zero?
			    (modulo index n)) (cons (car list) (recur (cdr list) (1+ index)))]
			  [else (recur (cdr list) (1+ index))]))])
    (recur list 0)))

(define (every-2th-element list)
  (every-nth-element 2 list))


;;# Exercise 1.6 (Creation of association list)
;;? Program a function pair-up that constructs an association list from a list of keys and a list of values
;;? Think of a reasonable solution in case the length of the key list is different from the length of the value list.
(define (pair-up keys values)
  (cond [(null? keys) '()]
	[(null? values) '()]
	[else (cons (cons (car keys) (car values))
		    (pair-up (cdr keys) (cdr values)))]))
  
;;# Exercise 1.7 (Association list and property lists)
;;? Program a function that converts an association list to a property list.
(define (assoc->prop lst)
  (if (null? lst)
      '()
      (let ([elem (car lst)])
	(cons (car elem) (cons (cdr elem) (assoc->prop (cdr lst)))))))

;;? Next, program the function that converts a property list to an association list.
(define (prop->assoc lst)
  (if (null? lst)
      '()
      (cons (cons (car lst) (cadr lst)) (prop->assoc (cddr lst)))))

;;# Exercise 1.8
;;? The function should return the value of key in property-list. Like assoc, get-prop should return #f if key is not found in property-list.
;;? How will you handle the case where the property list is malformed - a property list with an odd number of elements?
(define (get-prop lst index)
  (cond [(null? lst) #f]
	[(null? (cdr lst)) #f]
	[(eqv? (car lst) index) (cadr lst)]
	[else (get-prop (cddr lst) index)]
	))

;;? Discuss pros and cons of property lists and get-prop, compared to association lists and assoc.
;; I don't see many pros of property lists, feels kind of like a hack.
;; If you get a snippet of a property list, it's impossible to know where keys and values are.
;; One pro is that they are easier to write out by hand.

;;? Does the #f value, returned in cases where we do not find the key, bother you?
;; YEEEES WTF
;; What if you want to store booleans, with the possability of having false values.
;; Then you have to wrap booleans in something else, like a one element list.

;;# Exercise (list tail counterpart)
;;? Program your own version of list-tail. Call it my-list-tail.
(define (my-list-tail lst index)
  (cond [(null? lst) '()]
	[(zero? index) lst]
	[else (my-list-tail (cdr lst) (1- index))]
	))

;;? Next, program a function list-prefix which is a prefix counterpart to list-tail. (list-prefix lst n) returns a prefix of the list of length n.
(define (list-prefix lst index)
  (cond [(null? lst) '()]
	[(zero? index) (cons (car lst) '())]
	[else (cons (car lst) (list-prefix (cdr lst) (1- index)))]
	))

;;? Reflect on the difference between these two functions. Which one is most expensive in terms of memory allocation?
;; list-prefix builds up a copy of the existing array with consts.
;; Therefore a new const is created at each recursive step of the evaluation, which requires more space.
;; my-list-tail can just return the existing tail, without allocating a new array.