7.9

Homework 10

home work!

Programming Language ISL+

Due Date: Friday April 02, 9pm

Purpose Warm-up Exercises; Project Part II

Expectations

This is a pair assignment. Remember that working in pairs means that you both work on the problems together, ideally by one person developing the solution, while the other person observes and comments. After a while, you switch roles. Working in pairs does not mean to divvy up the work between the two of you.

As with all assignments, you must upload one .rkt file (for the entire pair/team), in the language specified at the top of the assignment to the Handin Server. Using the wrong language will invalidate your submission and result in a score of 0, so please be careful.

Unless otherwise stated, all data and functions you design must be designed according to the data and function design recipes, resp., following all four steps in each case.

Your code must conform to the guidelines outlined in the style guide on the course website. The style guide will be updated as the semester progresses so please remember to read it before submitting each assignment.

Warm-Up Exercises

Exercise 1 [Mutual Recursion] Recall the Div data definition from Lecture 27:

(require 2htdp/image)
 
; A Div is one of:
; - String
; - Image
; - UL
; - OL
; an HTML page: a text, a picture, an unordered, or an ordered list.
(define div-1 "Hi!")
(define div-2 (circle 10 "solid" "red"))
(define (div-templ d)
  (... (cond [(string? d) ... d ...]
             [(image?  d) ... d ...]
             [(ul?     d) ... (ul-templ d) ...]
             [(ol?     d) ... (ol-templ d) ...])))
 
(define-struct ul [content])
(define-struct ol [content])
 
; A UL is a (make-ul [List-of Div])
; an unordered list of HTML divs
(define ul-0 (make-ul '()))
(define ul-1 (make-ul (list div-1 div-2)))
(define (ul-templ ul)
  (... (lod-templ (ul-content ul)) ...))
 
; A OL is a (make-ol [List-of Div])
; an ordered list of HTML divs
(define ol-0 (make-ol '()))
(define ol-1 (make-ol (list div-1 ul-1)))
(define (ol-templ ol)
  (... (lod-templ (ol-content ol)) ...))
 
(define div-3 ul-1)
(define div-4 ol-1)

Task: Design a function num-divs that accepts a Div and returns the total number of Divs inside of it, including itself. For example, an unordered list of three strings has four Divs: the UL and the three strings.

Exercise 2 [Multiple Complex Inputs] Design a function enumerate that takes a list of Images and produces an enumerated list of Images: each image from the first list is preceded by its position number, counting from 1, and a blank, using the TEXT-SIZE and TEXT-COLOR given below: "1. ". For example:

(define TEXT-SIZE  20)
(define TEXT-COLOR "black")
 
(define im-1 (square 10 "solid" "blue"))
(define im-2 (circle 10 "solid" "red"))
 
(check-expect (enumerate (list im-1 im-2))
              (list (beside (text "1. " TEXT-SIZE TEXT-COLOR) im-1)
                    (beside (text "2. " TEXT-SIZE TEXT-COLOR) im-2)))

Hint: revisit the zip function.

Project: Part II

In this part of the homework we extend our Editor from HW09 by three user-facing features: the ability to change the font size, the ability to display a help menu, and the ability to do a simple form of I/O, so you can store and re-load texts.

Revisiting the Data Design

We first revisit our design of a Buffer: "more features" demands "richer data containers".

Exercise 3 A Buffer so far consists of a list of Lines, a line number, and a column number. Extend it by (i) a PosInt representing the current font size (since we want to be able to change it), and (ii) a mode parameter: our buffer will have three possible modes: "EDIT", indicating the user is editing the buffer text, "MENU", indicating that a help menu is being displayed, and "SEARCH", indicating that the buffer is in search mode (not used in this homework, but you might as well set it up now).

To extend the buffer data design means to update all parts of the design recipe for a Buffer. You also need to scan the entire code to see what is impacted by this data extension. For example, any calls to make-buffer in your code now need to accommodate the new buffer fields!

This may seem a bit painful but is unavoidable in serious software development: initial data (and code) designs frequently need to be extended or revised.

Changing the Font Size

Exercise 4 As per Exercise 3, the buffer structure now contains the current font size of the buffer. Let’s add functionality to change it! First, think about two suitable keys to bind to decreasing and increasing the font size (two of the function keys, e.g. F1 and F2 [or the Mac equivalents] might be good choices).

Now design functions that decrease or increase the font size of the buffer. Make sure the font size is always at least 1 (a PosInt; font size 0 would cause an error). Don’t worry about the maximum font size—this may be machine-dependent (the fonts must be installed on your system), so we just trust that the user is reasonable and won’t press the increase-font-size key until the font size goes through the roof.

You should also define a constant for the default font size and use that when you construct the initial buffer in the big-bang function, to start the editor.

Help! Displaying a Help Menu

Exercise 5 As per Exercise 3, the buffer structure now has a MENU mode. Use a suitable key (such as Escape) to allow the user to toggle (switch back and forth between) modes EDIT and MENU. This key should be the only one recognized while in MENU mode; ignore all other user interactions in that mode.

Next, make your drawing function mode-aware, which means: it should call helper functions that take care of the drawing for each mode. You have already implemented the drawing function for the EDIT mode (HW09). Now, design the (very simple) drawing function for the MENU mode: this should simply display a constant image with basic help info for the user: tell them about the modes you have, how to switch between the modes, and how to decrease/increase the font size. You can include more info in this menu if you like.

You may want to define a string constant that contains the menu text. Your drawing function then simply renders this string as a text. Use an appropriate font size and color (define constants!). Use a color other than the normal text color, so that it is easily visible to the user that they are in MENU mode.

Input/Output Functionality

Normally one expects an Editor to be able to store the text buffer contents to a file, and read it back in. But this is a bit complicated and in particular cannot be done within the ISL+ language used for this homework.

We therefore implement a simplified version of I/O, which does, however, enable you to fully conserve and reuse any text you have written.

Exercise 6 Recall from HW09 that a Line is a string representing a single line of text and, therefore, does not contain any line separators. Define a 1-String constant LINE-SEP to represent the RETURN key: (define LINE-SEP "\n"). Now design data Text, which is a single string representing the entire text contained in some text buffer. In the string, lines are separated by LINE-SEP. Here is a Text representing three lines of a buffer:

(define text-0
  (string-append
    "About a hiring visit by Edsger Dijkstra (1930-2002)," LINE-SEP
    "a famous computer scientist:"                         LINE-SEP))

(note that the last line is empty). Make a nice Text example to use for yourself.

We now extend our main function, editor, such that it takes as input a Text and, upon termination, returns the buffer contents in Text form. You can then copy this string into a file and save it. Next time you run your editor, if you want to continue working on the same text, you just pass the Text as the input to the editor function.

Exercise 7 Design a function split that takes a string s and a character c (represented as a 1-String) and splits s into a list of substrings defined by c as separator. The occurrences of c are not part of the substrings in the output:

(check-expect (split "A|B|C|D"   "|") (list "A" "B" "C" "D"))
(check-expect (split "|A|B|C|D"  "|") (list "" "A" "B" "C" "D"))
(check-expect (split "|A|B|C|D|" "|") (list "" "A" "B" "C" "D" ""))
(check-expect (split "A"         "|") (list "A"))
(check-expect (split ""          "|") (list ""))
(check-expect (split "|"         "|") (list "" ""))
(check-expect (split "||"        "|") (list "" "" ""))

Hint: first split s into a list of characters (ISL+ has a function for that), and use fold (what else?) with a powerful combinator function. Use the check-expects above as guidance, with particular emphasis on the corner cases. You do not need to design check-expects beyond the ones given above.

Here is an important invariant: Let n be the number of occurrences of c in s. Then the output list has length n+1. Confirm all check-expects satisfy this invariant.

Exercise 8 Design a function text->lol that takes a Text and converts it into a [NEList-of Line], suitable for the Buffer data structure.

Now add to your main function editor an argument initial-text of type Text. Also, change the invocation of big-bang such that it converts the initial-text into a list of Lines and constructs an appropriate buffer from it. This will be your initial world state.

Exercise 9 Design a function lol->text that does the inverse of text->lol: it "exports" the buffer contents as a Text. Use fold. Now change the return value of your main function editor: instead of the final world state, we want to return the buffer contents, but not as a list of Line, but as a Text. Note that we "forget" the cursor position when exporting the buffer contents to Text. If we read in this Text later, we will position the cursor at the top-left.

Remember to update the signature and other DR parts for your editor function.