[SICP] Exercise 2.3

26 views
Skip to first unread message

Anne B

unread,
Aug 28, 2020, 2:36:02 PM8/28/20
to FIGG
I posted an answer to SICP Exercise 2.3:

https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/

Looking for feedback on two things especially. Other feedback welcome too.

1) I’m not sure I understood correctly what they wanted in this exercise. Did I do two different representations of a rectangle? And I’m not sure I understand well enough what they mean by “abstraction barriers”.

2) Still working on formatting and writing clarity.


Elliot Temple

unread,
Aug 28, 2020, 2:46:19 PM8/28/20
to fallibl...@googlegroups.com
On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:

> I posted an answer to SICP Exercise 2.3:
>
> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/
>
> Looking for feedback on two things especially. Other feedback welcome too.
>
> 1) I’m not sure I understood correctly what they wanted in this exercise. Did I do two different representations of a rectangle? And I’m not sure I understand well enough what they mean by “abstraction barriers”.

You should think about this more instead of glossing over the problem and trying to move on. You’re confused about what you’re doing. You presumably need to review some of the previous material that this builds on.

Do you know what a “representation” is? Try to answer your own questions and if you get stuck, share the context + thing you’re stuck on.

Elliot Temple
www.curi.us

Anne B

unread,
Aug 29, 2020, 4:44:23 PM8/29/20
to FIGG
On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:

> On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:
>
>> I posted an answer to SICP Exercise 2.3:
>>
>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/
>>
>> Looking for feedback on two things especially. Other feedback welcome too.
>>
>> 1) I’m not sure I understood correctly what they wanted in this exercise. Did I do two different representations of a rectangle? And I’m not sure I understand well enough what they mean by “abstraction barriers”.
>
> You should think about this more instead of glossing over the problem and trying to move on. You’re confused about what you’re doing. You presumably need to review some of the previous material that this builds on.

I recognized that I was confused by this exercise. But instead of doing more studying or research, I did the exercise and asked if I did it right. That was a mistake.

> Do you know what a “representation” is? Try to answer your own questions and if you get stuck, share the context + thing you’re stuck on.

I’m not sure what a “representation” is. I’ve got a fuzzy idea of it but not an exact one. Here’s some stuff from the text on representations, along with my comments:

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1

> The basic idea of data abstraction is to structure the programs that are to use compound data objects so that they operate on ``abstract data.'' That is, our programs should use data in such a way as to make no assumptions about the data that are not strictly necessary for performing the task at hand. At the same time, a ``concrete'' data representation is defined independent of the programs that use the data. The interface between these two parts of our system will be a set of procedures, called selectors and constructors, that implement the abstract data in terms of the concrete representation.

They go through an example where they represent rational numbers as pairs.

> Pairs offer a natural way to complete the rational-number system. Simply represent a rational number as a pair of two integers: a numerator and a denominator.


This part confused me a little:

> Any complex data structure can be represented in a variety of ways with the primitive data structures provided by a programming language.

But pairs aren't primitive data structures in Scheme:

> To enable us to implement the concrete level of our data abstraction, our language provides a compound structure called a pair, which can be constructed with the primitive procedure cons.

So I think the authors are representing rational numbers as pairs, which aren’t primitive data structures, but can themselves be represented as primitive data structures (we don’t need to know how right now).

Another part that confused me:

> The difference between this implementation and the previous one lies in when we compute the gcd. If in our typical use of rational numbers we access the numerators and denominators of the same rational numbers many times, it would be preferable to compute the gcd when the rational numbers are constructed. If not, we may be better off waiting until access time to compute the gcd. In any case, when we change from one representation to the other, the procedures add-rat, sub-rat, and so on do not have to be modified at all.

By “change from one representation to the other”, do they mean change from computing the gcd when they make the pair to computing the gcd when they retrieve one part of the pair? Is changing the representation the same as changing the implementation? I think no. I think the representation is when they associate a rational number with a pair, and the implementation is the set of procedures used to make the pairs and to retrieve the values from the pairs. So they are changing implementations here. But are they changing representations? They are changing whether the numbers in the pair have a gcd other than 1. Is that changing the representation? I tentatively think yes but I’m not sure.

More on representation:

> Exercise 2.2. Consider the problem of representing line segments in a plane. Each segment is represented as a pair of points: a starting point and an ending point. Define a constructor make-segment and selectors start-segment and end-segment that define the representation of segments in terms of points. Furthermore, a point can be represented as a pair of numbers: the x coordinate and the y coordinate.

What I did for the first part of Exercise 2.3 seems to be an extension of this. I represented a rectangle as a pair of segments and also used the representations from Exercise 2.2 of segments and points.

I implemented that representation by writing procedures to put two segments into a pair to make a rectangle and to retrieve either segment from the rectangle representation.


I searched for “representation computing” and “data representation” and didn’t find anything that was the same as what they’re saying here in SICP. Maybe more searching and/or better search terms would help.

I’m stopping here for now. I’ll think about this some more and maybe get some feedback. Then I can move on to the second part of the exercise (implementing a different representation for rectangles such that the same procedures for perimeter and area will work) and to abstraction barriers.


Elliot Temple

unread,
Aug 29, 2020, 6:48:33 PM8/29/20
to fallibl...@googlegroups.com
On Aug 29, 2020, at 1:44 PM, Anne B <anne...@gmail.com> wrote:

> On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:
>
>> On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:
>>
>>> I posted an answer to SICP Exercise 2.3:
>>>
>>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/
>>>
>>> Looking for feedback on two things especially. Other feedback welcome too.
>>>
>>> 1) I’m not sure I understood correctly what they wanted in this exercise. Did I do two different representations of a rectangle? And I’m not sure I understand well enough what they mean by “abstraction barriers”.
>>
>> You should think about this more instead of glossing over the problem and trying to move on. You’re confused about what you’re doing. You presumably need to review some of the previous material that this builds on.
>
> I recognized that I was confused by this exercise. But instead of doing more studying or research, I did the exercise and asked if I did it right. That was a mistake.

That’s not what I think happened. At the link, after reviewing 3 solutions, you wrote: “ I think my answer is okay”.

>
>> Do you know what a “representation” is? Try to answer your own questions and if you get stuck, share the context + thing you’re stuck on.
>
> I’m not sure what a “representation” is. I’ve got a fuzzy idea of it but not an exact one. Here’s some stuff from the text on representations, along with my comments:
>
> https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1
>
>> The basic idea of data abstraction is to structure the programs that are to use compound data objects so that they operate on ``abstract data.'' That is, our programs should use data in such a way as to make no assumptions about the data that are not strictly necessary for performing the task at hand. At the same time, a ``concrete'' data representation is defined independent of the programs that use the data. The interface between these two parts of our system will be a set of procedures, called selectors and constructors, that implement the abstract data in terms of the concrete representation.
>
> They go through an example where they represent rational numbers as pairs.
>
>> Pairs offer a natural way to complete the rational-number system. Simply represent a rational number as a pair of two integers: a numerator and a denominator.
>
>
> This part confused me a little:
>
>> Any complex data structure can be represented in a variety of ways with the primitive data structures provided by a programming language.
>
> But pairs aren't primitive data structures in Scheme:
>
>> To enable us to implement the concrete level of our data abstraction, our language provides a compound structure called a pair, which can be constructed with the primitive procedure cons.

Pairs are primitives in Scheme. I don’t think you know what “primitive” means.


Elliot Temple
www.curi.us

Anne B

unread,
Aug 30, 2020, 4:54:10 AM8/30/20
to FIGG
On Aug 29, 2020, at 6:48 PM, Elliot Temple <cu...@curi.us> wrote:

> On Aug 29, 2020, at 1:44 PM, Anne B <anne...@gmail.com> wrote:
>
>> On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:
>>
>>> On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:
>>>
>>>> I posted an answer to SICP Exercise 2.3:
>>>>
>>>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/
>>>>
>>>> Looking for feedback on two things especially. Other feedback welcome too.
>>>>
>>>> 1) I’m not sure I understood correctly what they wanted in this exercise. Did I do two different representations of a rectangle? And I’m not sure I understand well enough what they mean by “abstraction barriers”.
>>>
>>> You should think about this more instead of glossing over the problem and trying to move on. You’re confused about what you’re doing. You presumably need to review some of the previous material that this builds on.
>>
>> I recognized that I was confused by this exercise. But instead of doing more studying or research, I did the exercise and asked if I did it right. That was a mistake.
>
> That’s not what I think happened. At the link, after reviewing 3 solutions, you wrote: “ I think my answer is okay”.

True, I did write that.

New description of what happened: I did the exercise, then read other answers, then said my answer was okay, then published my answer, then posted to FI that I wasn’t sure if I understood the exercise. At what point did I recognize consciously that I was confused? Now I’m not sure.

I need to improve at knowing when I do and don’t understand things.

Anne B

unread,
Aug 30, 2020, 6:26:12 PM8/30/20
to FIGG
On Aug 29, 2020, at 6:48 PM, Elliot Temple <cu...@curi.us> wrote:

> On Aug 29, 2020, at 1:44 PM, Anne B <anne...@gmail.com> wrote:
>
>> On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:
>>
>>> On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:
>>>
>>>> I posted an answer to SICP Exercise 2.3:
>>>>
>>>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/


>> This part confused me a little:
>>
>>> Any complex data structure can be represented in a variety of ways with the primitive data structures provided by a programming language.
>>
>> But pairs aren't primitive data structures in Scheme:
>>
>>> To enable us to implement the concrete level of our data abstraction, our language provides a compound structure called a pair, which can be constructed with the primitive procedure cons.
>
> Pairs are primitives in Scheme. I don’t think you know what “primitive” means.

I don’t really know what “primitive” means in a programming context. I looked into it some more.

SICP intro to Chapter 2:

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-13.html

> We concentrated in chapter 1 on computational processes and on the role of procedures in program design. We saw how to use primitive data (numbers) and primitive operations (arithmetic operations), how to combine procedures to form compound procedures through composition, conditionals, and the use of parameters, and how to abstract procedures by using define.

They mean that numbers are primitive data. But they don’t necessarily mean that all primitive data are numbers.

> From the perspective of the procedure linear-combination, it is irrelevant what a, b, x, and y are and even more irrelevant how they might happen to be represented in terms of more primitive data.

“more primitive data” means that there are degrees of primitiveness of data.

> One key idea in dealing with compound data is the notion of closure -- that the glue we use for combining data objects should allow us to combine not only primitive data objects, but compound data objects as well.

I think this implies that primitive data objects and compound data objects are mutually exclusive categories.

SICP section 2.1:

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1

> Data abstraction is a methodology that enables us to isolate how a compound data object is used from the details of how it is constructed from more primitive data objects.

“more primitive data objects”. This is similar to “more primitive data” above. Is it the same? It still implies that being primitive is a matter of degree.

> To enable us to implement the concrete level of our data abstraction, our language provides a compound structure called a pair, which can be constructed with the primitive procedure cons.

A pair is a “compound structure”. Is that the same as a “compound data object” from the quote above? Maybe not? Because it it’s the same, and I read correctly that “primitive data objects” are different from “compound data objects”, then pairs wouldn’t be “primitive data objects”. So then when Elliot says “Pairs are primitives in Scheme”, he must mean something different by “primitives” than “primitive data objects”. This is confusing.

I’m going to search outside of SICP for “primitive”.

https://www.webopedia.com/TERM/P/primitive.html

> In programming, primitives are the basic operations supported by the programming language.

This seems clear. But it’s talking about operations, not data or data structures. So in Scheme, primitives are the procedures that come already defined. That’s how I’d been thinking of primitive procedures.

An analogous meaning for primitive data structures would be data structures that come already in Scheme. In that sense, pairs are primitive because Scheme recognizes them without telling it anything additional.

https://whatis.techtarget.com/definition/primitive

> 1) In computer programming, a primitive (pronounced PRIH-muh-teev ) is a basic interface or segment of code that can be used to build more sophisticated program elements or interfaces.

This is a different meaning than the one just above it, right?

https://en.wikipedia.org/wiki/Primitive_data_type

> In computer science, primitive data type is either of the following:[citation needed]
>
> • a basic type is a data type provided by a programming language as a basic building block. Most languages allow more complicated composite types to be recursively constructed starting from basic types.
>
> • a built-in type is a data type for which the programming language provides built-in support.
>
> In most programming languages, all basic data types are built-in. In addition, many languages also provide a set of composite data types.

By this definition, pairs could be a primitive data type in Scheme, since they are built in. My guess is that “composite” here means the same thing as “compound” in the SICP quotes, which is “built up from something more basic”.

https://en.wikipedia.org/wiki/Scheme_(programming_language)

> Disjointness of primitive datatypes[edit]
> In Scheme the primitive datatypes are disjoint. Only one of the following predicates can be true of any Scheme object: boolean?, pair?, symbol?, number?, char?, string?, vector?, port?, procedure?.

This confirms that pairs are “primitive datatypes” in Scheme. Are “primitive data structure”, “primitive data object”, and “primitive datatype” all the same thing? I don’t know.

What I want to do is say that yes those are all the same thing, and that they are data types that are built into a programming language. But I’ve got too many unanswered questions to do that yet.

Max Kaye

unread,
Aug 31, 2020, 11:56:53 AM8/31/20
to fallibl...@googlegroups.com
On Sun, 30 Aug 2020 18:26:10 -0400
Anne B <anne...@gmail.com> wrote:

>On Aug 29, 2020, at 6:48 PM, Elliot Temple <cu...@curi.us> wrote:
>
>> On Aug 29, 2020, at 1:44 PM, Anne B <anne...@gmail.com> wrote:
>>
>>> On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:
>>>
>>>> On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:
>>>>
>>>>> I posted an answer to SICP Exercise 2.3:
>>>>>
>>>>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/
>
>
>>> This part confused me a little:
>>>
>>>> Any complex data structure can be represented in a variety of ways with the primitive data structures provided by
>>>> a programming language.
>>>
>>> But pairs aren't primitive data structures in Scheme:
>>>
>>>> To enable us to implement the concrete level of our data abstraction, our language provides a compound structure
>>>> called a pair, which can be constructed with the primitive procedure cons.
>>
>> Pairs are primitives in Scheme. I don’t think you know what “primitive” means.
>
>I don’t really know what “primitive” means in a programming context. I looked into it some more.
>
>SICP intro to Chapter 2:
>
>https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-13.html
>
>> We concentrated in chapter 1 on computational processes and on the role of procedures in program design. We saw how
>> to use primitive data (numbers) and primitive operations (arithmetic operations), how to combine procedures to form
>> compound procedures through composition, conditionals, and the use of parameters, and how to abstract procedures by
>> using define.
>
>They mean that numbers are primitive data. But they don’t necessarily mean that all primitive data are numbers.

Numbers are often primitives.

They don't *have* to be, though - I implemented positive integers (and plus / minus) using lists:
https://repl.it/repls/DearEducatedPort

The way I think of primitives is that they're the magic stuff the interpreter (or compile) gives you. There's no
definition file in scheme for integers - they're sort of implicitly defined by the interpreter. Likewise there's
(apparently) no definition for what a pair/list is written in scheme.

The main reason for this is speed. Adding numbers the normal way is much faster than my example because there are
dedicated CPU instructions for adding numbers and the interpreter knows how to use them. My way needs to go through
lots of scheme functions and do a lot more work to add two numbers.

>> From the perspective of the procedure linear-combination, it is irrelevant what a, b, x, and y are and even more
>> irrelevant how they might happen to be represented in terms of more primitive data.
>
>“more primitive data” means that there are degrees of primitiveness of data.

Sort of - the book isn't wrong but you can also look at primitiveness as yes/no. Primitives are usually numbers,
strings, lists, true/false, that sort of thing. Either data is a primitive or it's made of other data. If it's made of
other data, that data *might* be primitive, or it could be other combinations of data. (there's no limit on this, btw)

Example: a key-value store (also called a map). let's say we have some functions:

; just an empty map
(empty)

; take a map `m` and set the key `k` to point to the value `v`
; it should overwrite older values for the same key
(set k v m)

; take a map `m` and get the value pointed to by `k`
(get k m)

what might `m` look like as data? One way would be a list of pairs, where each pair stores a k,v pair. If we did that:

- `(empty)` would just return an empty list.

- `(set k v m)` would look for some existing key=k,
- if it found one it'd return a list that was *nearly* the same as m, except the old pair with key `k` would now have
the new value `v`.
- if it didn't find one it'd return the original list with the pair `(k v)` appended to it

- `(get k m)` would search the list for some key=k and return the associated value if it found the right key or do
something else if it didn't (either crash, or return null or something)

Can you see how our map is made of other data structures (lists and pairs) so it's not primitive?

Note: I'm not sure if lists are primitives in scheme; I get the feeling they're just nested pairs, and pairs are
primitives.


>> One key idea in dealing with compound data is the notion of closure -- that the glue we use for combining data
>> objects should allow us to combine not only primitive data objects, but compound data objects as well.
>
>I think this implies that primitive data objects and compound data objects are mutually exclusive categories.

Yup.

>SICP section 2.1:
>
>https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1
>
>> Data abstraction is a methodology that enables us to isolate how a compound data object is used from the details of
>> how it is constructed from more primitive data objects.
>
>“more primitive data objects”. This is similar to “more primitive data” above. Is it the same? It still implies that
>being primitive is a matter of degree.

Yes, it's still the same.

One way you can think about "more primitive data": how many layers of abstraction is the data structure building on?

If you have a number - that's a primitive (unless you're doing silly things like my example above)
If you have a *map of strings to numbers* - that's not a primitive
If you have a *map of strings to (a map of numbers to numbers)* - that's not a primitive

one place you might have a map of strings to (a map of numbers to numbers) is like phone prefixes. you could do like:
(get 10036 (get "NY" m)) ; returns 202 maybe

in some sense our map of strings to a map of numbers to numbers is "less primitive" than just a map of strings to
numbers, but they're also both *not primitives*. However, the map of maps has more abstraction between it and primitive
values.

>> To enable us to implement the concrete level of our data abstraction, our language provides a compound structure
>> called a pair, which can be constructed with the primitive procedure cons.
>
>A pair is a “compound structure”. Is that the same as a “compound data object” from the quote above? Maybe not?
>Because it it’s the same, and I read correctly that “primitive data objects” are different from “compound data
>objects”, then pairs wouldn’t be “primitive data objects”. So then when Elliot says “Pairs are primitives in Scheme”,
>he must mean something different by “primitives” than “primitive data objects”. This is confusing.

> A pair is a “compound structure”. Is that the same as a “compound data object” from the quote above?

No, I think they mean it's just made of other stuff. It can still be a primitive because it's defined by the
interpreter and not implemented in scheme.

>I’m going to search outside of SICP for “primitive”.
>
>https://www.webopedia.com/TERM/P/primitive.html
>
>> In programming, primitives are the basic operations supported by the programming language.
>
>This seems clear. But it’s talking about operations, not data or data structures. So in Scheme, primitives are the
>procedures that come already defined. That’s how I’d been thinking of primitive procedures.

Primitives can be data and procedures/functions (b/c they can be anything not written in the language itself, provided
by the runtime).

The line between them is actually blurry. like you can think of the number `0` as a shortcut for "the result of a
function which returns zero". that might sound circular but languages don't *start* with numbers defined, the symbols
in source code need to be interpreted into something computers understand. that's where the interpreter comes in.

>An analogous meaning for primitive data structures would be data structures that come already in Scheme. In that
>sense, pairs are primitive because Scheme recognizes them without telling it anything additional.

Yeah, that's a decent way to think about it.

>https://whatis.techtarget.com/definition/primitive
>
>> 1) In computer programming, a primitive (pronounced PRIH-muh-teev ) is a basic interface or segment of code that can
>> be used to build more sophisticated program elements or interfaces.
>
>This is a different meaning than the one just above it, right?

Different level of abstraction, but roughly the same idea.

>https://en.wikipedia.org/wiki/Primitive_data_type
>
>> In computer science, primitive data type is either of the following:[citation needed]
>>
>> • a basic type is a data type provided by a programming language as a basic building block. Most languages
>> allow more complicated composite types to be recursively constructed starting from basic types.
>>
>> • a built-in type is a data type for which the programming language provides built-in support.
>>
>> In most programming languages, all basic data types are built-in. In addition, many languages also provide a set of
>> composite data types.
>
>By this definition, pairs could be a primitive data type in Scheme, since they are built in. My guess is that
>“composite” here means the same thing as “compound” in the SICP quotes, which is “built up from something more basic”.

Yes, but annoyingly it is simplistic - languages can provide complex types as primitives.

Example: usually you can think of "lists" and "arrays" to be the same thing in programming languages.
However, Purescript has `Array` as a primitive, but not `List`

* Documentation for Array: https://pursuit.purescript.org/builtins/docs/Prim#t:Array
* Documentation for List: https://pursuit.purescript.org/packages/purescript-lists/5.4.1/docs/Data.List.Types#t:List
* Definition for List:
https://github.com/purescript/purescript-lists/blob/62900a56f6864638c952575dfd211a1cc55be7da/src/Data/List/Types.purs#L36

>https://en.wikipedia.org/wiki/Scheme_(programming_language)
>
>> Disjointness of primitive datatypes[edit]
>> In Scheme the primitive datatypes are disjoint. Only one of the following predicates can be true of any Scheme
>> object: boolean?, pair?, symbol?, number?, char?, string?, vector?, port?, procedure?.
>
>This confirms that pairs are “primitive datatypes” in Scheme. Are “primitive data structure”, “primitive data object”,
>and “primitive datatype” all the same thing? I don’t know.

I given the bits you've copied I'd say it's safe to consider them the same thing. I'd say there are some subtle
differences between the terms, but you probably don't need to worry about it unless there's an issue that comes up.

Actually a grammar example might work well:

* datatypes are *types* of things, like "verb", "preposition", etc.
* a data structure is made of stuff, like *prepositional phrase*
* (note: "prepositional phrase" is also a type, but it's not primitive because we make it using other types)
* a data object is like "over the hill", it's an instantiation of a prepositional phrase (which is both a data
structure and data type)

>What I want to do is say that yes those are all the same thing, and that they are data types that are built into a
>programming language. But I’ve got too many unanswered questions to do that yet.





I wrote a bit about data types, data structures, and data objects if anyone is curious:

>This confirms that pairs are “primitive datatypes” in Scheme. Are “primitive data structure”, “primitive data object”,
>and “primitive datatype” all the same thing? I don’t know.

This sort of naming can change from language to language, but I would expect something like:

datatypes and data structures to be very similar or actually the same thing. A data structure is almost always referring
to non-primitives, particularly the stuff we have to implement in the language like a 'linked list'. data structures are
constructed in certain ways and have certain operations which are fast and slow (specific to the data structure). The
map I described above is a data structure.

A data *type* (or datatype) is either a conceptual thing like "a list of lists" or the name of the type
within the language, like "integer". Scheme is dynamically typed so the closest you get are the predicates you quoted
like `boolean?`, `pair?`. Other languages (which are statically typed) have explicit type systems that require you to
explicitly define new types you create (sort of like you define functions).

A data *object* is almost certainly talking about the *instantiation* of something with particular properties. It can
be used more generally too.


--
Max
xk.io

I post my FI work/articles/exercise/practice here:
https://xertrov.github.io/fi

Anne B

unread,
Sep 1, 2020, 12:05:22 PM9/1/20
to FIGG
Thank you. This helps some, although I am still confused by most of it. One thing I think I understand is what you are saying about data objects being instantiations (particular instances) of data dypes.

I do appreciate you taking the time to answer me, Max. But I don’t have good strategies for handling a lot of information at once, meaning the information from you and from all the other things I read. I have bad strategies like being paralyzed and doing nothing or giving up and moving on to something else. Actually, giving up on something and moving on to something else is sometimes a good strategy, but I’m not yet ready to do that with this topic.

=====

I decided to try writing out a small number of simple questions and requesting short, simple answers. If anyone is willing to help me, I’d appreciate short, simple answers to my questions and/or suggestions of other easy ways to proceed.

1) I think of Scheme primitives as things that Scheme already knows what to do with, without anyone telling it anything more. Is this a good enough definition for me to work with for now?

2) Can “primitive” be a matter of degree? If so, then my definition above is wrong or incomplete. Could it be that people use the same word “primitive” to mean two different things?

3) In Scheme, are pairs primitive data types? I think yes. Are they primitives? I think yes. Are they primitive data structures? I’m not sure.

=====

I also discovered that there are videos of lectures by the authors about the topics in the book. Justin pointed them (or similar ones) out in his first SICP video. I watched one of the videos (2B) and found it helpful. I plan to watch the other lectures about Chapters 1 and 2. Maybe I’ll find some answers about primitives in those.

https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/

Maybe it would also help me to do some searching in the book and read things ahead of where I am that might be relevant.


Max Kaye

unread,
Sep 1, 2020, 3:48:32 PM9/1/20
to fallibl...@googlegroups.com
On Tue, 1 Sep 2020 12:05:19 -0400
A data *type* is like the abstract idea of what it is. Examples: "integer", "string", "list of integers", "pair". Types
also get more complex (like types of functions), but this is enough atm.

An *instantiation* of that type is like: `1`, `"hello"`, `(1 2 3 4)`, `("hi", 2)`
this last one is a pair of type `(string, integer)`

Each instantiation has a *representation in memory* of the program, so the number `42` might be a 64bit integer, which
would mean it's memory representation might be b0000000000000000000000000000000000000000000000000000000000101010,
or 0x0000002a. ('b' is a common prefix for binary numbers, and '0x' a common prefix for hexadecimal)

`42` has a pattern it corresponds to in memory. "integer" doesn't have a corresponding patter in memory.

Does that help?

>I do appreciate you taking the time to answer me, Max. But I don’t have good strategies for handling a lot of
>information at once, meaning the information from you and from all the other things I read. I have bad strategies like
>being paralyzed and doing nothing or giving up and moving on to something else. Actually, giving up on something and
>moving on to something else is sometimes a good strategy, but I’m not yet ready to do that with this topic.

You're welcome. I'm glad it helps some.

I often write too much when replying to you, I think. I have an idea for a new reply-method^2 that might help both of
us:

* read through and take notes on what I might want to reply
* organise those things into coherent answers (sometimes I start replying to a paragraph - while still reading - and
there are relevant bits later)
* post the best few sentences I can for those answers (adding the stuff about using lists as numbers is maybe fun, but
was probably unnecessary)
* if possible find some other stuff to link to, both to avoid extra work on my part, and also b/c there are already
good explanations out there for a lot of this stuff; I should be efficient in finding good content.
* if I have anything that would be longer than that which I want to write more about, I should use it as a writing
exercise and host it on my site - then I can link to it (which reduces the amount in the post and might help avoid
things like being paralyzed somewhat).

I think this would make it easier for you to pick what to focus on and ask questions about. It also means I don't spend
time explaining something that doesn't need to be explained.

>=====
>
>I decided to try writing out a small number of simple questions and requesting short, simple answers. If anyone is
>willing to help me, I’d appreciate short, simple answers to my questions and/or suggestions of other easy ways to
>proceed.
>
>1) I think of Scheme primitives as things that Scheme already knows what to do with, without anyone telling it
>anything more. Is this a good enough definition for me to work with for now?

Yup, scheme just "knows" what an integer is how to add them. You don't need to tell scheme these things. (Sometimes you
might "import" (i.e. use) code someone else wrote, but that's just getting someone else to tell scheme how to do things
-- no imports are needed for using numbers or lists^1)

>2) Can “primitive” be a matter of degree? If so, then my definition above is wrong or incomplete. Could it be that
>people use the same word “primitive” to mean two different things?

Some people would say it can be a matter of degree. such a degree would start at 0 (i.e. primitive) and is unbounded in
the positive direction. in this case, degree is roughly like "the number of layers of abstraction" away from primitive
types.

Some people would say it's not a matter of degree. they think the scale is just 0 or 1. however, they won't disagree
that "layers of abstraction" exist and you can count them.

note: *how* you'd count them is arguable, but I don't think it's important here.

>3) In Scheme, are pairs primitive data types? I think yes. Are they primitives? I think yes. Are they primitive data
>structures? I’m not sure.

I think yes to all 3.

However, there is a subtlety: "a pair of integers" is not a *primitive type* even though a pair is. you don't need to
know the type of the elements to use the primitive functions like 'car' or 'cdr', they just output whatever is first or
second. also: you get functions like `pair?` but not `pair-of-ints?`.

>=====
>
>I also discovered that there are videos of lectures by the authors about the topics in the book. Justin pointed them
>(or similar ones) out in his first SICP video. I watched one of the videos (2B) and found it helpful. I plan to watch
>the other lectures about Chapters 1 and 2. Maybe I’ll find some answers about primitives in those.
>
>https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/

That's super neat!

>Maybe it would also help me to do some searching in the book and read things ahead of where I am that might be
>relevant.

I sometimes do this, but can't think of a time I thought it was a particularly good thing to do.

[1]: some languages automatically import a bunch of functions for you (sometimes called the "prelude" module, sometimes
not given an explicit name). the functions that get imported aren't primitives.

[2]: I said "reply-method" b/c I wasn't sure about phrases like "replying method" or "method of replying" and
"reply-method" is shorter and (I think) clear enough.

Anne B

unread,
Sep 2, 2020, 6:38:05 AM9/2/20
to FIGG
Thank you. I think this is enough for me to move on to learning about the next thing on my list.

Anne B

unread,
Sep 3, 2020, 5:59:26 AM9/3/20
to FIGG
On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:

I’m trying to figure out what they mean in this book by “implementation” and “representation”. I need to understand this to do Exercise 2.3.

Here’s part of the rational number example.

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1

They give two different sets of procedures:

> (define (make-rat n d)
> (let ((g (gcd n d)))
> (cons (/ n g) (/ d g))))

> (define (numer x) (car x))
> (define (denom x) (cdr x))

and

> (define (make-rat n d)
> (cons n d))
> (define (numer x)
> (let ((g (gcd (car x) (cdr x))))
> (/ (car x) g)))
> (define (denom x)
> (let ((g (gcd (car x) (cdr x))))
> (/ (cdr x) g)))

They say, about these two sets of procedures:

> The difference between this implementation and the previous one lies in when we compute the gcd. If in our typical use of rational numbers we access the numerators and denominators of the same rational numbers many times, it would be preferable to compute the gcd when the rational numbers are constructed. If not, we may be better off waiting until access time to compute the gcd. In any case, when we change from one representation to the other, the procedures add-rat, sub-rat, and so on do not have to be modified at all.

According to this paragraph, both the implementation and the representation changed when they changed the three procedures.

My current guess about what “implementation” and “representation” mean for this example: “implementation” means the three procedures. “representation” is about how the numbers are stored (or maybe not literally stored but we can think of it that way). In the first case the rational number is stored as a pair of integers that are relatively prime, and in the second case the rational number is stored as a pair of integers that are not necessarily relatively prime.


Elliot Temple

unread,
Sep 3, 2020, 12:13:27 PM9/3/20
to fallibl...@googlegroups.com
On Sep 1, 2020, at 9:05 AM, Anne B <anne...@gmail.com> wrote:

> On Aug 31, 2020, at 11:56 AM, Max Kaye <m...@xk.io> wrote:
>
>> On Sun, 30 Aug 2020 18:26:10 -0400
>> Anne B <anne...@gmail.com> wrote:
>>
>>> On Aug 29, 2020, at 6:48 PM, Elliot Temple <cu...@curi.us> wrote:
>>>
>>>> On Aug 29, 2020, at 1:44 PM, Anne B <anne...@gmail.com> wrote:
>>>>
>>>>> On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:
>>>>>
>>>>>> On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:
>>>>>>
>>>>>>> I posted an answer to SICP Exercise 2.3:
>>>>>>>
>>>>>>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/


> I also discovered that there are videos of lectures by the authors about the topics in the book. Justin pointed them (or similar ones) out in his first SICP video. I watched one of the videos (2B) and found it helpful. I plan to watch the other lectures about Chapters 1 and 2. Maybe I’ll find some answers about primitives in those.
>
> https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/

You should also try the SICP video lectures by Brian Harvey from UC Berkeley.

Elliot Temple
www.curi.us

Anne B

unread,
Sep 3, 2020, 1:33:45 PM9/3/20
to FIGG
On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:

I’ve reviewed the previous material quite a bit, and a little of the material after this. I’m still stuck. I wonder if I’m missing some big-picture idea here.

Here’s the exercise:

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_thm_2.3

> Exercise 2.3. Implement a representation for rectangles in a plane. (Hint: You may want to make use of exercise 2.2.)[1] In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle. Now implement a different representation for rectangles. Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will work using either representation?


My current questions (other than the definitions of “implementation” and “representation”, which I discussed in a separate email):

1) The contract for rational numbers example in the text was: if x is the result of doing (make-rat n d), then (numer x)/(denom x)= n/d. What’s the corresponding contract for this exercise? In other words, what conditions do my constructor and selector procedures (“make-rectangle”, “side1” and “side2” in this case) have to satisfy? Is it just that (constructor (selector1 r) (selector2 r)) has to return r? There should be more to it, but I don’t know how to say it. I want (perimeter r) to return the correct perimeter of the rectangle and (area r) to return the correct area of the rectangle.

2) Perhaps related: The arguments to “perimeter” or “area” will be made with “make-rectangle”, right? How is it determined what the arguments to “make-rectangle” look like? Can I say they must be two segments that share a common first point? I don’t know if that’s allowed. For my two different representations, can I require different things as arguments to “make-rectangle”? It looks like this answer did (https://codology.net/post/sicp-solution-exercise-2-3/) and I also did in my first try at the exercise.



[1]

> Exercise 2.2. Consider the problem of representing line segments in a plane. Each segment is represented as a pair of points: a starting point and an ending point. Define a constructor make-segment and selectors start-segment and end-segment that define the representation of segments in terms of points. Furthermore, a point can be represented as a pair of numbers: the x coordinate and the y coordinate. Accordingly, specify a constructor make-point and selectors x-point and y-point that define this representation. Finally, using your selectors and constructors, define a procedure midpoint-segment that takes a line segment as argument and returns its midpoint (the point whose coordinates are the average of the coordinates of the endpoints). To try your procedures, you'll need a way to print points:
>
> (define (print-point p)
> (newline)
> (display "(")
> (display (x-point p))
> (display ",")
> (display (y-point p))
> (display ")"))




Max Kaye

unread,
Sep 4, 2020, 2:00:44 AM9/4/20
to fallibl...@googlegroups.com
On Thu, 3 Sep 2020 05:48:21 -0400
Anne B <anne...@gmail.com> wrote:

>On Aug 28, 2020, at 2:46 PM, Elliot Temple <cu...@curi.us> wrote:
>
>> On Aug 28, 2020, at 11:35 AM, Anne B <anne...@gmail.com> wrote:
>>
>>> I posted an answer to SICP Exercise 2.3:
>>>
>>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/
>>>
>>> Looking for feedback on two things especially. Other feedback welcome too.
>>>
>>> 1) I’m not sure I understood correctly what they wanted in this exercise. Did I do two different representations of
>>> a rectangle? And I’m not sure I understand well enough what they mean by “abstraction barriers”.
>>
>> You should think about this more instead of glossing over the problem and trying to move on. You’re confused about
>> what you’re doing. You presumably need to review some of the previous material that this builds on.
>>
>> Do you know what a “representation” is? Try to answer your own questions and if you get stuck, share the context +
>> thing you’re stuck on.
>
>I’m trying to figure out what they mean in this book by “implementation” and “representation”. I need to understand
>this to do Exercise 2.3.

my intuition is:

an *implementation* is the code you write. you could implement a function to increment a number like:
`(define (increment n) (+ n 1))`
but you could also do it like:
`(define (increment-again n) (/ (+ (* 2 n) 2) 2))`
[I think that's right, but haven't checked, it's meant to be `f(x) = (2x+2)/2`]

a *representation of X* is how you represent something as data -- usually in terms of other data structures/types. So
you could represent a circle as the coordinates for its center and radius: (x0, y0, r0) or something. (This data type is
called a triple, or a 3-tuple, or a threeple^1)

so the implementation of a function like "make-circle" might be:

`(define (make-circle x0 y0 r0) (mk-triple x0 y0 r0))`

note: I'm not sure what `mk-triple` might look like in scheme, maybe `'(x0 y0 r0)` or something.


[1]: I'm not sure anyone else calls a 3-tuple a 'threeple'; I started calling them that a few years ago because "tuple"
can be pronounced two-pull (the other pronunciation is tup-el)


>Here’s part of the rational number example.
>
>https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1
>
>They give two different sets of procedures:
>
>> (define (make-rat n d)
>> (let ((g (gcd n d)))
>> (cons (/ n g) (/ d g))))
>
>> (define (numer x) (car x))
>> (define (denom x) (cdr x))
>
>and
>
>> (define (make-rat n d)
>> (cons n d))
>> (define (numer x)
>> (let ((g (gcd (car x) (cdr x))))
>> (/ (car x) g)))
>> (define (denom x)
>> (let ((g (gcd (car x) (cdr x))))
>> (/ (cdr x) g)))

Yup, so those are two different implementations of *the functions* for manipulating rational numbers. You can think of
the *set of functions* for some data type (rational numbers being a data type) as the *implementation* of that data
type.

>They say, about these two sets of procedures:
>
>> The difference between this implementation and the previous one lies in when we compute the gcd. If in our typical
>> use of rational numbers we access the numerators and denominators of the same rational numbers many times, it would
>> be preferable to compute the gcd when the rational numbers are constructed. If not, we may be better off waiting
>> until access time to compute the gcd. In any case, when we change from one representation to the other, the
>> procedures add-rat, sub-rat, and so on do not have to be modified at all.
>
>According to this paragraph, both the implementation and the representation changed when they changed the three
>procedures.

the implementations changed because the functions do different stuff, and the representation changed because the
*meaning* behind the data changed. It looks like both representations are pairs of integers, but the meaning behind
those paris is different. One is reduced (the first implementation) and the other one is not reduced (the second
implementation).

By "reduced" I mean the same thing as "simplified", as in "the answer to 'simplify 2/8' is '1/4'

>My current guess about what “implementation” and “representation” mean for this example: “implementation” means the
>three procedures. “representation” is about how the numbers are stored (or maybe not literally stored but we can think
>of it that way). In the first case the rational number is stored as a pair of integers that are relatively prime, and
>in the second case the rational number is stored as a pair of integers that are not necessarily relatively prime.

yup. I'd be more specific about what "implementation" means, tho; like you couldn't mix and match those functions - the
precise *set* of those functions matters.

Max Kaye

unread,
Sep 4, 2020, 4:09:44 AM9/4/20
to fallibl...@googlegroups.com
"What's the corresponding contract?" is a good question to ask, but I don't think it's necessary to answer 2.3.

> Is it just that (constructor (selector1 r) (selector2 r)) has to return r?

It's more than that, though that property is important. We know it's more than that because that property fits other
things as well, like `(pair (car p) (cdr p)) == p` for pairs generally. What other properties do rectangles have? Are
there other facts you could write down?

As a starting point: how many different rectangles can you make with `(make-square _ _)`?

I added "hint1" at the end with more detail.

>2) Perhaps related: The arguments to “perimeter” or “area” will be made with “make-rectangle”, right? How is it
>determined what the arguments to “make-rectangle” look like? Can I say they must be two segments that share a common
>first point? I don’t know if that’s allowed. For my two different representations, can I require different things as
>arguments to “make-rectangle”? It looks like this answer did (https://codology.net/post/sicp-solution-exercise-2-3/)
>and I also did in my first try at the exercise.


> How is it determined what the arguments to “make-rectangle” look like?

That's up to you and the implementations you choose.

You could use side lengths, or pairs of coordinates for each side (make sure they're at right angles, tho), or you
could use 4 coordinates for each corner, or only two coordinates for two opposite corners (but you also need to know
the orientation; does the rectangle have any lines that aren't exactly horizontal or vertical?)

> Can I say they must be two segments that share a common first point? I don’t know if that’s allowed.

I think it's up to you. I think it would be fair to always have (0,0) as one of the corners.

> For my two different representations, can I require different things as
>arguments to “make-rectangle”?

Why not? Does the question say anything about that?


The meat of the question is:

>> Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will
>> work using either representation?

What does this imply about the implementation of `(area r)` and `(perimeter r)`?
Does the representation of `r` matter?
When does it matter?

also hint2 below

> [1]
>
>> Exercise 2.2. Consider the problem of representing line segments in a plane. Each segment is represented as a pair
>> of points: a starting point and an ending point. Define a constructor make-segment and selectors start-segment and
>> end-segment that define the representation of segments in terms of points. Furthermore, a point can be represented
>> as a pair of numbers: the x coordinate and the y coordinate. Accordingly, specify a constructor make-point and
>> selectors x-point and y-point that define this representation. Finally, using your selectors and constructors,
>> define a procedure midpoint-segment that takes a line segment as argument and returns its midpoint (the point whose
>> coordinates are the average of the coordinates of the endpoints). To try your procedures, you'll need a way to print
>> points:
>>
>> (define (print-point p)
>> (newline)
>> (display "(")
>> (display (x-point p))
>> (display ",")
>> (display (y-point p))
>> (display ")"))

I think the authors' suggestion is related to representing things as segments or points.

Particularly that you could use the answers to 2.2 in 2.3.





(hint below)





...




hint1:

what could you do with two *different* rectangles made using `(constructor a b)` and `(constructor b a)`? what
properties need to be the same for both rectangles?



(hint2 below)




hint2:

>> Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will
>> work using either representation?

So the main criterion is that the definitions of both perimeter and area use sets of functions that are interchangeable.

what functions can you think of which:
1. you can implement for both implementations you write, and
2. you can use to calculate area and perimeter

I think if you ignore the question for a bit and write two different implementations, that will help.
Once you've done that try and write *different* area and perimeter functions for each implementation.

Don't worry about whether "the same perimeter and area procedures will work using either representation" yet - do that
after you've written the implementation and perimeter/area functions.

Anne B

unread,
Sep 4, 2020, 6:07:35 AM9/4/20
to FIGG
Thank you.

I found them here:

https://www.youtube.com/playlist?list=PLhMnuBfGeCDNgVzLPxF9o5UNKG1b-LFY9

I’ve watched the first four so far and plan to watch them up through the ninth one soon to catch up to where I am in SICP.

Brian Harvey is one of the authors of Simply Scheme. Someone studying Simply Scheme might find these videos useful too.

Anne B

unread,
Sep 4, 2020, 8:21:43 PM9/4/20
to FIGG
On Aug 28, 2020, at 2:35 PM, Anne B <anne...@gmail.com> wrote:

> I posted an answer to SICP Exercise 2.3:
>
> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/

My original answer was wrong because it did not give two different representations. I think I have a correct answer now.


The exercise is:

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_thm_2.3

> Exercise 2.3. Implement a representation for rectangles in a plane. (Hint: You may want to make use of exercise 2.2.) In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle. Now implement a different representation for rectangles. Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will work using either representation?



For the first rectangle implementation representation, the two input segments need to be perpendicular and they need to meet. They are stored as a pair.

(define (make-rectangle s1 s2) ; constructor
(cons s1 s2))

(define (side1 rectangle) ; selector
(car rectangle))

(define (side2 rectangle) ; selector
(cdr rectangle))


The procedures to calculate perimeter and area are in terms of the selectors:

(define (perimeter r)
(* 2 (+ (length (side1 r)) (length (side2 r)))))

(define (area r)
(* (length (side1 r)) (length (side2 r))))


Helper procedures:

(define (length segment)
(distance (start-segment segment) (end-segment segment)))

(define (distance p1 p2)
(sqrt (+ (square (- (x-point p1) (x-point p2)))
(square (- (y-point p1) (y-point p2))))))

(define (square x)
(* x x))

(define (make-segment p q)
(cons p q))

(define (start-segment segment)
(car segment))

(define (end-segment segment)
(cdr segment))

(These last three procedures are from Exercise 2.2.)


Next, an implementation of a different representation. The two input segments again need to be perpendicular, but now the second point in the first one and the first point in the second one need to be the same. They are stored as a pair, with the first part of the pair being the first endpoint of the first segment and the second part of the pair being the second segment.

(define (make-rectangle2 s1 s2) ; constructor
(cons (start-segment s1) s2))

(define (side1 r) ; selector
(make-segment (car r) (car (cdr r))))

(define (side2 r) ; selector
(cdr r))


The same perimeter and area procedures work with this implementation.


(I’ve got more to say about this exercise, which I’ll post separately.)

Elliot Temple

unread,
Sep 4, 2020, 8:31:46 PM9/4/20
to FIGG
You aren’t actually trying to make reasonable representations of rectangles. You also appear to have intentionally made the representations similar to try to minimize doing what the problem wants you to do.

Elliot Temple
www.elliottemple.com

Anne B

unread,
Sep 4, 2020, 8:45:40 PM9/4/20
to FIGG
What would a reasonable representation of a rectangle have that’s not in this answer? From what you said, it looks like I don’t understand what the goal is in making a representation.

Anne B

unread,
Sep 5, 2020, 4:38:29 AM9/5/20
to FIGG
I think it’s the crux of what I’m not understanding about how to do the exercise. But it’s hard for me to know that because I don’t have an answer for it and I don’t understand what the exercise is asking.

>> Is it just that (constructor (selector1 r) (selector2 r)) has to return r?
>
> It's more than that, though that property is important. We know it's more than that because that property fits other
> things as well, like `(pair (car p) (cdr p)) == p` for pairs generally. What other properties do rectangles have? Are
> there other facts you could write down?

Four corners.

Four sides.

The sides have the corners as endpoints. But not all combinations of corners have sides with them as endpoints.

Two of the sides are parallel. The other two sides are parallel. The two sets of parallel lines are perpendicular to each other.

I don’t know how to put this information about rectangles into the procedures I write. I don’t know if I’m supposed to put this information into the procedures I write.

> As a starting point: how many different rectangles can you make with `(make-square _ _)`?

Hmm. I don’t understand this question. I don’t know what “make-square” would look like.

> I added "hint1" at the end with more detail.
>
>> 2) Perhaps related: The arguments to “perimeter” or “area” will be made with “make-rectangle”, right? How is it
>> determined what the arguments to “make-rectangle” look like? Can I say they must be two segments that share a common
>> first point? I don’t know if that’s allowed. For my two different representations, can I require different things as
>> arguments to “make-rectangle”? It looks like this answer did (https://codology.net/post/sicp-solution-exercise-2-3/)
>> and I also did in my first try at the exercise.
>
>
>> How is it determined what the arguments to “make-rectangle” look like?
>
> That's up to you and the implementations you choose.
>
> You could use side lengths, or pairs of coordinates for each side (make sure they're at right angles, tho), or you
> could use 4 coordinates for each corner, or only two coordinates for two opposite corners (but you also need to know
> the orientation; does the rectangle have any lines that aren't exactly horizontal or vertical?)

Okay, it makes sense to me that I could use each of those things. Is "make sure they're at right angles” something I should have in my procedures, and if so, do I just check for it and output an error if it’s not true, or is there some other way to make it part of the procedures? (I’m not quite sure what I’m asking here.)

> 4 coordinates for each corner

I think you mean 4 sets of two coordinates, one set for each corner?

> two coordinates for two opposite corners

Two sets of coordinates?

>> Can I say they must be two segments that share a common first point? I don’t know if that’s allowed.
>
> I think it's up to you. I think it would be fair to always have (0,0) as one of the corners.
>
>> For my two different representations, can I require different things as
>> arguments to “make-rectangle”?
>
> Why not? Does the question say anything about that?

I’m thinking that "In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle” and "Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will work using either representation?” mean that the constructors and selectors that are used in the perimeter and area procedures (which might not be all of them) have to have the same names in order to both be used by the perimeter and area procedures and also the same meanings in order to give the correct answers for perimeter and area. Maybe I have this idea wrong?

> The meat of the question is:
>
>>> Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will
>>> work using either representation?
>
> What does this imply about the implementation of `(area r)` and `(perimeter r)`?
> Does the representation of `r` matter?
> When does it matter?

I think I answered this in my previous paragraph.

> also hint2 below
>
>> [1]
>>
>>> Exercise 2.2. Consider the problem of representing line segments in a plane. Each segment is represented as a pair
>>> of points: a starting point and an ending point. Define a constructor make-segment and selectors start-segment and
>>> end-segment that define the representation of segments in terms of points. Furthermore, a point can be represented
>>> as a pair of numbers: the x coordinate and the y coordinate. Accordingly, specify a constructor make-point and
>>> selectors x-point and y-point that define this representation. Finally, using your selectors and constructors,
>>> define a procedure midpoint-segment that takes a line segment as argument and returns its midpoint (the point whose
>>> coordinates are the average of the coordinates of the endpoints). To try your procedures, you'll need a way to print
>>> points:
>>>
>>> (define (print-point p)
>>> (newline)
>>> (display "(")
>>> (display (x-point p))
>>> (display ",")
>>> (display (y-point p))
>>> (display ")"))
>
> I think the authors' suggestion is related to representing things as segments or points.

I agree.

> Particularly that you could use the answers to 2.2 in 2.3.

I agree.

> hint1:
>
> what could you do with two *different* rectangles made using `(constructor a b)` and `(constructor b a)`? what
> properties need to be the same for both rectangles?

I’m not sure what you mean by “do with”. And wouldn’t the answer to your second question depend on the implementation? What if a and b are different kinds of things, like one is a point and one is a side?

> hint2:
>
>>> Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will
>>> work using either representation?
>
> So the main criterion is that the definitions of both perimeter and area use sets of functions that are interchangeable.
>
> what functions can you think of which:
> 1. you can implement for both implementations you write, and
> 2. you can use to calculate area and perimeter

Width and height could be used to calculate both perimeter and area. I could write width and height procedures for any implementation. But I was reading "In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle” to mean that unless width and height are selectors in both implementations or can be calculated in the perimeter and area procedures from the same-named selectors of both implementations, I can’t use them. Maybe I’ve got this wrong?

> I think if you ignore the question for a bit and write two different implementations, that will help.
> Once you've done that try and write *different* area and perimeter functions for each implementation.
>
> Don't worry about whether "the same perimeter and area procedures will work using either representation" yet - do that
> after you've written the implementation and perimeter/area functions

I’ll make this part a separate email.

Anne B

unread,
Sep 5, 2020, 4:53:43 AM9/5/20
to FIGG
I intentionally made the representations similar because I thought it was necessary to do the problem at all. The fact that you think I was doing it to try to minimize doing what the problem wants me to do is a strong indication that I don’t understand what the problem wants me to do.

Maybe my answers to Max’s last email will point to what it is that I don’t get about this exercise.



Anne B

unread,
Sep 5, 2020, 7:30:33 PM9/5/20
to FIGG
On Sep 4, 2020, at 4:09 AM, Max Kaye <m...@xk.io> wrote:

> On Thu, 3 Sep 2020 13:33:43 -0400
> Anne B <anne...@gmail.com> wrote:


>> Here’s the exercise:
>>
>> https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_thm_2.3
>>
>>> Exercise 2.3. Implement a representation for rectangles in a plane. (Hint: You may want to make use of exercise
>>> 2.2.)[1] In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a
>>> given rectangle. Now implement a different representation for rectangles. Can you design your system with suitable
>>> abstraction barriers, so that the same perimeter and area procedures will work using either representation?


> hint2:
>
>>> Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will
>>> work using either representation?
>
> So the main criterion is that the definitions of both perimeter and area use sets of functions that are interchangeable.
>
> what functions can you think of which:
> 1. you can implement for both implementations you write, and
> 2. you can use to calculate area and perimeter
>
> I think if you ignore the question for a bit and write two different implementations, that will help.
> Once you've done that try and write *different* area and perimeter functions for each implementation.
>
> Don't worry about whether "the same perimeter and area procedures will work using either representation" yet - do that
> after you've written the implementation and perimeter/area functions.

Okay, here are two different implementations of rectangle representations, each with their own different set of perimeter and area procedures. Keep in mind that I still don’t know if I understand what’s supposed to happen in the exercise.

These first six procedures are the segment and point representations that I wrote for the previous exercise. It’s possible they could be wrong, although other people’s answers I found online had the same procedures.

(define (make-segment p q)
(cons p q))

(define (start-segment segment)
(car segment))

(define (end-segment segment)
(cdr segment))

(define (make-point x y)
(cons x y))

(define (x-point point)
(car point))

(define (y-point point)
(cdr point))



Representation 1. The two input segments need to be perpendicular and they need to meet. They are stored as a pair.

(define (make-rectangle1 s1 s2)
(cons s1 s2))

(define (side1 rectangle)
(car rectangle))

(define (side2 rectangle)
(cdr rectangle))

The procedures to calculate perimeter and area:

(define (distance p1 p2)
(sqrt (+ (square (- (x-point p1) (x-point p2)))
(square (- (y-point p1) (y-point p2))))))

(define (square x)
(* x x))

(define (length segment)
(distance (start-segment segment) (end-segment segment)))

(define (perimeter r)
(* 2 (+ (length (side1 r)) (length (side2 r)))))

(define (area r)
(* (length (side1 r)) (length (side2 r))))



Representation 2. The three input points need to form a right angle, with the right angle at the second one. They are stored as a pair, with the first part of the pair containing the first point and the second part of the pair containing another pair which contains the second and third points.

(define (make-rectangle2 p1 p2 p3)
(cons p1 (cons p2 p3)))

(define (point1 r)
(car r))

(define (point2 r)
(car (cdr r)))

(define (point3 r)
(cdr (cdr r)))

The procedures to calculate perimeter and area:

(define (distance p1 p2)
(sqrt (+ (square (- (x-point p1) (x-point p2)))
(square (- (y-point p1) (y-point p2))))))

(define (square x)
(* x x))

(define (perimeter r)
(* 2 (+ (distance (point1 r) (point2 r)) (distance (point2 r) (point3 r)))))

(define (area r)
(* ((distance (point1 r) (point2 r)) (distance (point2 r) (point3 r)))))



Anne B

unread,
Sep 5, 2020, 8:01:46 PM9/5/20
to FIGG
On Sep 4, 2020, at 8:21 PM, Anne B <anne...@gmail.com> wrote:

> The exercise is:
>
> https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_thm_2.3
>
>> Exercise 2.3. Implement a representation for rectangles in a plane. (Hint: You may want to make use of exercise 2.2.) In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle. Now implement a different representation for rectangles. Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will work using either representation?

Here’s part of an answer to this exercise that I found online. I have a question about it.

https://codology.net/post/sicp-solution-exercise-2-3/

> (define (perimeter-rect r)
> (* 2 (+ (width-rect r) (height-rect r))))
>
> (define (area-rect r)
> (* (width-rect r) (height-rect r)))


> ; Constructor
>
> (define (make-rect p1 p2 p3)
> (if (orthogonal? (sub-vector p2 p1) (sub-vector p3 p1))
> (cons p1 (cons p2 p3))
> (error "Points should make an rectangle."))) ; check orthogonality, which is longer? (error "Argument not 0 or 1: CONS" m)
>
> (define (p1-rect r) (car r))
> (define (p2-rect r) (car (cdr r)))
> (define (p3-rect r) (cdr (cdr r)))
>
>
> ; Public interface
>
> (define (height-rect r) (distance-point (p1-rect r) (p2-rect r)))
> (define (width-rect r) (distance-point (p1-rect r) (p3-rect r)))

I think “p1-rect”, “p2-rect” and “p3-rect” are selectors.

Are “height-rect” and “width-rect” also selectors? If yes, that conflicts with my understanding of what a selector is and might explain what I don’t understand about this exercise. If no, then is the answer wrong because the perimeter and area procedures are in terms of them?

Max Kaye

unread,
Sep 6, 2020, 9:57:11 PM9/6/20
to fallibl...@googlegroups.com
On Sat, 5 Sep 2020 04:38:26 -0400
>> [...]
>> hint1:
>>
>> what could you do with two *different* rectangles made using `(constructor a b)` and `(constructor b a)`? what
>> properties need to be the same for both rectangles?
>
>I’m not sure what you mean by “do with”. And wouldn’t the answer to your second question depend on the implementation?
>What if a and b are different kinds of things, like one is a point and one is a side?

(just a quick reply on this)

say we have:

r1 = make_rect(a, b)
r2 = make_rect(b, a)

The two rectangles (r1 and r2) are not equal (they're similar but one is flipped along y=x).

does perim(r1) == perim(r2)? (perimeter)
does area(r1) == area(r2)?

Anne B

unread,
Sep 7, 2020, 4:34:49 PM9/7/20
to FIGG
Yes, the two rectangles would have the same perimeter and area. But I still don’t know where you’re going with this.

Anne B

unread,
Sep 9, 2020, 1:36:20 PM9/9/20
to FIGG
To be more specific, I think that selectors each need to return an argument that can be put into the constructor. In the answer above, “height-rect” and “width-rect” each return a single number, and you can’t put those height and width numbers into “make-rectangle”, which takes points as arguments.

I think that selectors each need to return an argument that can be put into the constructor because the examples in the book and an example in Brian Harvey's video and class notes (I plan to post that example separately) all do that. But I could be wrong about it. Maybe other good examples wouldn’t work that way.

If anyone knows whether this is correct or not, please tell me whether it is.

Here’s another example I found of an exercise answer where the selectors don’t return the same kinds of things that are arguments to the constructor:

http://wiki.drewhess.com/wiki/SICP_exercise_2.03

> Here are rectangle constructor and the width and height selectors:
>
> (define (make-rectangle p1 p2 p3)
> (cons (make-segment p1 p2) (make-segment p2 p3)))
>
> (define (rectangle-width r)
> (segment-length (cdr r)))
>
> (define (rectangle-height r)
> (segment-length (car r)))


Anne B

unread,
Sep 9, 2020, 2:00:21 PM9/9/20
to FIGG
Here’s the example from Brian Harvey’s video and class notes. The video is here:

https://www.youtube.com/watch?v=8LIZqnf7gIs

The class notes are here, in the pages marked in the document as 284-285:

https://inst.eecs.berkeley.edu/~cs61a/reader/notes.pdf

I think this example is analogous to what is asked for in SICP Exercise 2.3. Harvey presents two different sets of constructor (make-card) and selector (rank, suit) procedures. The two sets both take in the same kinds of data. Both sets can be used with the same procedures that put the cards into a hand and total the hand.

From the class notes, the first constructor procedure:

> (define (make-card rank suit)
> (word rank (first suit)) )


From the video, the first selector procedures:

> (define card-rank butlast)
> (define card-suit last)

(He’s using “word”, “butlast”, “last”, from Simply Scheme.)

From the class notes, the second set of constructor and selector procedures, with his comments:

> Once we’re using data abstraction we can change the implementation of the data type without affecting the programs that use that data type. This means we can change how we represent a card, for example, without rewriting total:
>
> ;;;;; In file cs61a/lectures/2.1/total.scm
>
> (define (make-card rank suit)
> (cond ((equal? suit ’heart) rank)
> ((equal? suit ’spade) (+ rank 13))
> ((equal? suit ’diamond) (+ rank 26))
> ((equal? suit ’club) (+ rank 39)) (else (error "say what?")) ))
>
> (define (rank card) (remainder card 13))
>
> (define (suit card)
> (nth (quotient card 13) ’(heart spade diamond club)))
>
> We have changed the internal representation so that a card is now just a number between 1 and 52 (why? maybe we’re programming in FORTRAN) but we haven’t changed the behavior of the program at all. We still call total the same way.

“total” is the procedure that adds up the values of the cards in a hand. There’s also a “make-hand” procedure that makes cards into a sentence with one word for each card. Both of these would work with either set of “make-card”/“rank”/“suit” procedures.

Anyone have an opinion on whether this card-totaling example is the kind of thing that’s being asked for in SICP Exercise 2.3? I think it is.

Anne B

unread,
Sep 9, 2020, 2:26:39 PM9/9/20
to FIGG
I haven’t yet figured out what a reasonable representation of a rectangle would have that’s not in this answer. If someone’s got an idea for me, please let me know.

I can try to address Elliot’s second criticism by making my representations less similar. I can still have my first constructor make two input segments into a pair of segments but have my second constructor make the same two input segments into a list of three points. But maybe those are still too similar to get at what the problem wants us to do?


Anne B

unread,
Sep 9, 2020, 4:38:24 PM9/9/20
to FIGG
Wait. I just noticed an example in the book where this isn’t true. It’s their last implementation of rational numbers.

https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1

> For example, an alternate way to address the problem of reducing rational numbers to lowest terms is to perform the reduction whenever we access the parts of a rational number, rather than when we construct it. This leads to different constructor and selector procedures:
>
> (define (make-rat n d)
> (cons n d))
> (define (numer x)
> (let ((g (gcd (car x) (cdr x))))
> (/ (car x) g)))
> (define (denom x)
> (let ((g (gcd (car x) (cdr x))))
> (/ (cdr x) g)))

Let r be the rational number (make-rat 6 8).

Then (constructor (selector1 r) (selector2 r)) does not return r.

r is (make-rat 6 8), which is (cons 6 8), which is the pair (6 . 8).

And (make-rat (numer r) (denom r)) is (make-rat 3 4), which is the pair (3 . 4).

But this, that I wrote above, is true:

>>> 1) The contract for rational numbers example in the text was: if x is the result of doing (make-rat n d), then (numer
>>> x)/(denom x)= n/d. What’s the corresponding contract for this exercise?


So I think I need to come up with contract items that we want to hold true for rectangles.

Back to quoting Max and me:

>> It's more than that, though that property is important. We know it's more than that because that property fits other
>> things as well, like `(pair (car p) (cdr p)) == p` for pairs generally. What other properties do rectangles have? Are
>> there other facts you could write down?
>
> Four corners.
>
> Four sides.
>
> The sides have the corners as endpoints. But not all combinations of corners have sides with them as endpoints.
>
> Two of the sides are parallel. The other two sides are parallel. The two sets of parallel lines are perpendicular to each other.
>
> I don’t know how to put this information about rectangles into the procedures I write. I don’t know if I’m supposed to put this information into the procedures I write.

So I think I am supposed to put this kind of information about rectangles into my procedures. Still not sure how.

Max Kaye

unread,
Sep 9, 2020, 11:09:06 PM9/9/20
to fallibl...@googlegroups.com
I agree, particularly: the return the *exact* data that went into the constructor.

In general, for a constructor that takes exactly 1 argument:

(constructor (selector d1) == d1)

> In the answer above, “height-rect” and “width-rect” each return a single number, and you can’t put those height and width numbers into “make-rectangle”, which takes points as arguments.

So in this case they're not selectors, they're just normal functions.

**Note**: the quote you give below contradicts this.

>I think that selectors each need to return an argument that can be put into the constructor because the examples in the book and an example in Brian Harvey's video and class notes (I plan to post that example separately) all do that. But I could be wrong about it. Maybe other good examples wouldn’t work that way.
>
>If anyone knows whether this is correct or not, please tell me whether it is.

With the caveat above (selectors return the *exact* data that went in) - I think that's correct.

However, the following quote contradicts this, so I'm not quite sure why the Authors use the term 'selector'

>Here’s another example I found of an exercise answer where the selectors don’t return the same kinds of things that are arguments to the constructor:
>
>http://wiki.drewhess.com/wiki/SICP_exercise_2.03
>
>> Here are rectangle constructor and the width and height selectors:
>>
>> (define (make-rectangle p1 p2 p3)
>> (cons (make-segment p1 p2) (make-segment p2 p3)))
>>
>> (define (rectangle-width r)
>> (segment-length (cdr r)))
>>
>> (define (rectangle-height r)
>> (segment-length (car r)))

I don't know why the authors say this - like I would think that would make perimeter and area functions selectors too, which I don't think makes sense.

Maybe their generalisation of selector is a function which takes some data and returns like exactly one thing about that data, but that doesn't seem reasonable when applied to stuff like area/perimeter.

Anne B

unread,
Sep 10, 2020, 4:18:35 AM9/10/20
to FIGG
I was thinking this at first too. But then I thought about this example from the book. I’m quoting myself in this post from yesterday:

https://groups.google.com/d/msg/fallible-ideas/ErcZk3tL7BQ/XhOkdKh2AQAJ

> Wait. I just noticed an example in the book where this isn’t true. It’s their last implementation of rational numbers.
>
> https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1
>
>> For example, an alternate way to address the problem of reducing rational numbers to lowest terms is to perform the reduction whenever we access the parts of a rational number, rather than when we construct it. This leads to different constructor and selector procedures:
>>
>> (define (make-rat n d)
>> (cons n d))
>> (define (numer x)
>> (let ((g (gcd (car x) (cdr x))))
>> (/ (car x) g)))
>> (define (denom x)
>> (let ((g (gcd (car x) (cdr x))))
>> (/ (cdr x) g)))
>
> Let r be the rational number (make-rat 6 8).
>
> Then (constructor (selector1 r) (selector2 r)) does not return r.
>
> r is (make-rat 6 8), which is (cons 6 8), which is the pair (6 . 8).
>
> And (make-rat (numer r) (denom r)) is (make-rat 3 4), which is the pair (3 . 4).

Maybe I’m doing something wrong? From this example I conclude that it’s not always true that selectors return the exact data that went into the constructor.

Back to quoting Max’s post.

>> In the answer above, “height-rect” and “width-rect” each return a single number, and you can’t put those height and width numbers into “make-rectangle”, which takes points as arguments.
>
> So in this case they're not selectors, they're just normal functions.

That’s my understanding too. But I’m tentative about it.

> **Note**: the quote you give below contradicts this.
>
>> I think that selectors each need to return an argument that can be put into the constructor because the examples in the book and an example in Brian Harvey's video and class notes (I plan to post that example separately) all do that. But I could be wrong about it. Maybe other good examples wouldn’t work that way.
>>
>> If anyone knows whether this is correct or not, please tell me whether it is.
>
> With the caveat above (selectors return the *exact* data that went in) - I think that's correct.
>
> However, the following quote contradicts this, so I'm not quite sure why the Authors use the term 'selector'

The quote below is not from the authors. It’s from someone who did the exercises.

>> Here’s another example I found of an exercise answer where the selectors don’t return the same kinds of things that are arguments to the constructor:
>>
>> http://wiki.drewhess.com/wiki/SICP_exercise_2.03
>>
>>> Here are rectangle constructor and the width and height selectors:
>>>
>>> (define (make-rectangle p1 p2 p3)
>>> (cons (make-segment p1 p2) (make-segment p2 p3)))
>>>
>>> (define (rectangle-width r)
>>> (segment-length (cdr r)))
>>>
>>> (define (rectangle-height r)
>>> (segment-length (car r)))
>
> I don't know why the authors say this - like I would think that would make perimeter and area functions selectors too, which I don't think makes sense.
>
> Maybe their generalisation of selector is a function which takes some data and returns like exactly one thing about that data, but that doesn't seem reasonable when applied to stuff like area/perimeter.

This answer doesn’t make sense to me either.


Alisa Zinov'yevna Rosenbaum

unread,
Sep 10, 2020, 11:08:51 PM9/10/20
to fallibl...@googlegroups.com
I agree that height-rect and width-rect are regular functions, *not* selectors. However, the perimeter and area functions are still "in terms of" the selectors, just indirectly, because perimeter and area call functions (height-rect and width-rect) which themselves make use of the selectors.

>>> To be more specific, I think that selectors each need to return an argument that can be put into the constructor.
>>
>> I agree, particularly: the return the *exact* data that went into the constructor.
>>
>> In general, for a constructor that takes exactly 1 argument:
>>
>> (constructor (selector d1) == d1)

In this case, I think you should only compare what you read from the selectors, not the underlying representation returned from the constructor. So the actual constructor/selector equivalence criterion would be this: for any one-argument constructor C, valid constructor argument X, and corresponding selector S, we must have

(equal
(S (C (S (C X))))
(S (C X)))

> I was thinking this at first too. But then I thought about this example from the book. I’m quoting myself in this post from yesterday:
>
> https://groups.google.com/d/msg/fallible-ideas/ErcZk3tL7BQ/XhOkdKh2AQAJ
>
>> Wait. I just noticed an example in the book where this isn’t true. It’s their last implementation of rational numbers.
>>
>> https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_sec_2.1
>>
>>> For example, an alternate way to address the problem of reducing rational numbers to lowest terms is to perform the reduction whenever we access the parts of a rational number, rather than when we construct it. This leads to different constructor and selector procedures:
>>>
>>> (define (make-rat n d)
>>> (cons n d))
>>> (define (numer x)
>>> (let ((g (gcd (car x) (cdr x))))
>>> (/ (car x) g)))
>>> (define (denom x)
>>> (let ((g (gcd (car x) (cdr x))))
>>> (/ (cdr x) g)))
>>
>> Let r be the rational number (make-rat 6 8).
>>
>> Then (constructor (selector1 r) (selector2 r)) does not return r.
>>
>> r is (make-rat 6 8), which is (cons 6 8), which is the pair (6 . 8).
>>
>> And (make-rat (numer r) (denom r)) is (make-rat 3 4), which is the pair (3 . 4).
>
> Maybe I’m doing something wrong? From this example I conclude that it’s not always true that selectors return the exact data that went into the constructor.

If you extend my constructor/selector equivalence criterion to constructors with two arguments, it should hold for make-rat/numer/denom, i.e., we should have:

(equal
(numer (make-rat (numer (make-rat 6 8)) (denom (make-rat 6 8))))
(numer (make-rat 6 8)))

(equal
(denom (make-rat (numer (make-rat 6 8)) (denom (make-rat 6 8))))
(denom (make-rat 6 8)))

Anne B

unread,
Sep 11, 2020, 6:59:26 AM9/11/20
to FIGG
Ah yes. So we can think of height-rect and width-rect as being part of the perimeter and area functions.

But then, for this exercise, you’d want your second representation to use the same height-rect and width-rect procedures as well as the same perimeter and area procedures, right? That solution had different height-rect and width-rect procedures for its two different representations. Is that not what the exercise was asking for? I don’t think so but I’m not sure.

>>>> To be more specific, I think that selectors each need to return an argument that can be put into the constructor.
>>>
>>> I agree, particularly: the return the *exact* data that went into the constructor.
>>>
>>> In general, for a constructor that takes exactly 1 argument:
>>>
>>> (constructor (selector d1) == d1)
>
> In this case, I think you should only compare what you read from the selectors, not the underlying representation returned from the constructor. So the actual constructor/selector equivalence criterion would be this: for any one-argument constructor C, valid constructor argument X, and corresponding selector S, we must have
>
> (equal
> (S (C (S (C X))))
> (S (C X)))

Okay. This makes sense.
Yes, these hold true.

Max Kaye

unread,
Sep 11, 2020, 9:07:10 AM9/11/20
to fallibl...@googlegroups.com
The height-rect and width-rect functions are *dependencies* of the perimeter and area functions. I don't mean to introduce a new term if that's unfamiliar - it just means the perimeter and area functions depend on the other two. That's what Alisa means with:

>> the perimeter and area functions are still "in terms of" the selectors

Anne B said:
>But then, for this exercise, you’d want your second representation to use the same height-rect and width-rect procedures as well as the same perimeter and area procedures, right?

No - that would be implementation specific. exceptions are: if there were another abstraction layer, or if they just happened to use some compatible implementation by chance (this 2nd would be very bad practice though)

> That solution had different height-rect and width-rect procedures for its two different representations. Is that not what the exercise was asking for? I don’t think so but I’m not sure.

the idea (I think) is not that the area and perimeter functions use *the same* functions under the hood, but that they use functions with the same *interface* (or type). That is:
- area and perimeter, as functions, only take entire rectangles
- area and perimeter use specially *named* functions (e.g. 'height-rect' and 'width-rect')
- those specifically named functions have a particular "shape" - i.e. they take a certain kind of thing (a rectangle) and return a certain kind of thing (the width of the sides)
- the *specific* functions (height-rect and width-rect) will have *different* implementations for each 'under the hood' implementation of rectangles you do
- so you should have 2 height-rect functions and 2 width-rect functions, and one pair takes rectangles of type R1, and the other pair takes rectangles of type R2

There's a concept called "duck typing" that might help you here. Links to an article with an accompanying video:

- https://devopedia.org/duck-typing
- https://www.youtube.com/watch?v=x3v9zMX1s4s

The idea is "if it looks like a duck and quacks like a duck, it's a duck". The rectangle is your duck. The way we see if it looks/quacks like a duck is via the functions (height-rect r) and (width-rect r). Metaphorically: if functions of those names have an implementation for some data of type R that returns a number, it's a duck.

Anne B

unread,
Sep 11, 2020, 1:27:48 PM9/11/20
to FIGG
None of the examples of representations in the book or in either set of video lectures have procedures like rect-width and rect-height, that return something unlike what’s put into the constructor and that are different for two different representations and that are needed for the procedures analagous to perimeter and area. So I’m not convinced that that’s what the exercise intends. Maybe we’ll see that kind of thing later in the course?

It seems to me that "In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle” means that perimeter and area have to be actually in terms of the constructors and selectors, not in terms of rect-width and rect-height, which are neither constructors nor selectors as far as I can tell, and that "the same perimeter and area procedures will work using either representation” implies that both implementations have to include selectors of the same names that are then used in the perimeter and area procedures.

I’ve found three more answers (pasted below) and they all use rect-width and rect-height procedures. This and all the previous posts about this exercise lead me to think that I’m reading the question wrong and/or my understanding of what a selector is is wrong. But I don’t see it yet.


https://wizardbook.wordpress.com/2010/11/30/exercise-2-3/

This one calls rect-width and rect-height selectors in one place and utilities in two other places.

> First the procedures that work on rectangles, these should be usable for any representation of a rectangle and therefore each representation will have to provide selectors called rect-width and rect-height.
>
> define (perimiter rectangle)
> (* 2 (+ (rect-width rectangle)
> (rect-height rectangle))))
>
> (define (area rectangle)
> (* (rect-width rectangle)
> (rect-height rectangle)))
>
> Rectangle implementation 1
>
> (define (perimeter rectangle)
> (* 2 (+ (rect-width rectangle)
> (rect-height rectangle))))
>
> (define (area rectangle)
> (* (rect-width rectangle)
> (rect-height rectangle)))
>
> (define (make-rectangle left-segment bottom-segment)
> (cons left-segment bottom-segment))
>
> ;; selectors
> (define (left-segment rectangle)
> (car rectangle))
>
> (define (bottom-segment rectangle)
> (cdr rectangle))
>
> ;; utilities
> (define (rect-width rectangle)
> (segment-length (bottom-segment rectangle)))
>
> (define (rect-height rectangle)
> (segment-length (left-segment rectangle)))
>
> (define r1 (make-rectangle
> (make-segment (make-point 4 8 )
> (make-point 4 16))
> (make-segment (make-point 4 8 )
> (make-point 20 8 ))))
> (area r1)
> 128
> (perimeter r1)
> 48
>
> Rectangle implementation 2
>
> (define (make-rectangle bottom-left top-right)
> (cons bottom-left top-right))
>
> ;; selectors
> (define (bottom-left rectangle)
> (car rectangle))
>
> (define (top-right rectangle)
> (cdr rectangle))
>
> ; not necessary but they make the utilities easier to read
> (define (top-left rectangle)
> (make-point (x-point (bottom-left rectangle))
> (y-point (top-right rectangle))))
>
> (define (bottom-right rectangle)
> (make-point (x-point (top-right rectangle))
> (y-point (bottom-left rectangle))))
>
> ;; utilities
> (define (rect-width rectangle)
> (segment-length (make-segment (bottom-left rectangle)
> (bottom-right rectangle))))
>
> (define (rect-height rectangle)
> (segment-length (make-segment (bottom-left rectangle)
> (top-left rectangle))))
>
> (define r2 (make-rectangle
> (make-point 4 8 )
> (make-point 20 16)))
> (area r2)
> 128
> (perimeter r2)
> 48


https://ivanovivan.wordpress.com/category/project-sicp/chapter-2/page/3/

This one has width-rect and height-rect as the only selectors listed.

> For the purposes of this exercise a rectangle will have two selectors width-rect, and height-rect for extracting the width and height respectively. Furthermore for sake of simplicity it is assumed that we are only interested in rectangles with sides parallel to the coordinate axes.
>
> Having specified these selectors we can directly jump ahead and implement the perimeter-rect and area-rect procedures:
>
> (define (perimeter-rect r)
> (+ (* 2 (width-rect r))
> (* 2 (height-rect r))))
>
> (define (area-rect r)
> (* (width-rect r)
> (height-rect r)))
>
> Now we can create different representations for a rectangle. The first representation treats a rectangle as a pair of points corresponding to diagonally opposite corners:
>
> ;; Representation 1
>
> (define (make-rect p1 p2)
> (cons p1 p2))
>
> (define (width-rect r)
> (abs (- (x-point (car r)) (x-point (cdr r)))))
>
> (define (height-rect r)
> (abs (- (y-point (car r)) (y-point (cdr r)))))
>
> The second representation considers a rectangle as a point corresponding to its lower left corner, a width, and a height:
>
> ;; Representation 2
>
> (define (make-rect p width height)
> (cons p (cons width height)))
>
> (define (width-rect r)
> (car (cdr r)))
>
> (define (height-rect r)
> (cdr (cdr r)))
>
> Changing the representation does not require changing the implementation of the perimeter-rect and area-rect procedures. This design technique is sometimes called programming to an interface, not an implementation.


https://eli.thegreenplace.net/2007/07/25/sicp-sections-211-212

This one has no selectors other than rect-width and rect-height, although it doesn’t label anything as a constructor or selector.

> If we define the interface to the rectangle abstraction, we can go on defining the computation of perimeters and areas without actually seeing the code for the rectangle:
>
> ; Rectangle abstraction:
> ;
> ; * make-rect: constructs a rectangle given its two opposing
> ; points
> ; * rect-width: returns the rectangle's width
> ; * rect-height: returns the rectangle's height
> ;
>
> (defun rect-perimeter (rect)
> (+ (* 2 (rect-width rect))
> (* 2 (rect-height rect))))
>
> (defun rect-area (rect)
> (* (rect-width rect)
> (rect-height rect)))
>
> And here are two different representations:
>
> ; Representation 1: stores the two opposing points
> ;
> (defun make-rect (p1 p2)
> (cons p1 p2))
>
> (defun rect-width (rect)
> (abs (- (x-point (car rect))
> (x-point (cdr rect)))))
>
> (defun rect-height (rect)
> (abs (- (y-point (car rect))
> (y-point (cdr rect)))))
>
> ; Representation 2: stores the diagonal segment
> ;
> (defun make-rect (p1 p2)
> (make-segment p1 p2))
>
> (defun rect-width (rect)
> (abs (- (x-point (start-segment rect))
> (x-point (end-segment rect)))))
>
> (defun rect-height (rect)
> (abs (- (y-point (start-segment rect))
> (y-point (end-segment rect)))))
>
> These two representations are very similar, and we can easily envision others. For example: store a “width segment” and a “height segment”, or store all 4 points, or store one corner stone, width, height and the angle of one of them above the X plane.


Max Kaye

unread,
Sep 12, 2020, 12:12:23 AM9/12/20
to fallibl...@googlegroups.com
Try these two:

A rectangle represented by side lengths only. (the constructor would take 2 numbers)
(make-rect 12 7)

A rectangle represented by the ratio of side lengths and a scaling factor. (the constructor would take a rational number - as in make-rat - and a number)
(make-rect (make-rat 12 7) 12)

The two examples would produce different data with different representations, but the *rectangles* themselves would be congruent.

These rectangles don't require any checking of parameters and all possible rectangles are represented. If you don't want to deal with negative numbers as inputs you could check the values are >0 or just wrap all the values in an `abs` function (absolute value).

Max Kaye

unread,
Sep 12, 2020, 12:13:34 AM9/12/20
to fallibl...@googlegroups.com
Whoops, this should be:
(make-rect (make-rat 12 7) 7)

(presuming make-rat takes the numerator then the denominator)

Anne B

unread,
Sep 13, 2020, 8:06:00 PM9/13/20
to FIGG


> On Sep 12, 2020, at 12:13 AM, Max Kaye <m...@xk.io> wrote:
>
> On Sat, 12 Sep 2020 14:12:14 +1000 Max Kaye <m...@xk.io> wrote:
>
>> On Wed, 9 Sep 2020 14:26:37 -0400 Anne B <anne...@gmail.com> wrote:
>>
>>> On Sep 4, 2020, at 8:45 PM, Anne B <anne...@gmail.com> wrote:
>>>
>>>> On Sep 4, 2020, at 8:31 PM, Elliot Temple <cu...@curi.us> wrote:
>>>>
>>>>> On Sep 4, 2020, at 5:21 PM, Anne B <anne...@gmail.com> wrote:
>>>>>
>>>>>> On Aug 28, 2020, at 2:35 PM, Anne B <anne...@gmail.com> wrote:
>>>>>>
>>>>>>> I posted an answer to SICP Exercise 2.3:
>>>>>>>
>>>>>>> https://aelanwave.wordpress.com/2020/08/28/sicp-exercise-2-3/
>>>>>>
>>>>>> My original answer was wrong because it did not give two different representations. I think I have a correct answer now.
>>>>>>
>>>>>>
>>>>>> The exercise is:
>>>>>>
>>>>>> https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-14.html#%_thm_2.3
>>>>>>
>>>>>>> Exercise 2.3. Implement a representation for rectangles in a plane. (Hint: You may want to make use of exercise 2.2.) In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle. Now implement a different representation for rectangles. Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will work using either representation?


>> Try these two:
>>
>> A rectangle represented by side lengths only. (the constructor would take 2 numbers)
>> (make-rect 12 7)
>>
>> A rectangle represented by the ratio of side lengths and a scaling factor. (the constructor would take a rational number - as in make-rat - and a number)
>> (make-rect (make-rat 12 7) 12)
>
> Whoops, this should be:
> (make-rect (make-rat 12 7) 7)
>
> (presuming make-rat takes the numerator then the denominator)
>
>> The two examples would produce different data with different representations, but the *rectangles* themselves would be congruent.
>>
>> These rectangles don't require any checking of parameters and all possible rectangles are represented. If you don't want to deal with negative numbers as inputs you could check the values are >0 or just wrap all the values in an `abs` function (absolute value).

Yes, these would be two different representations.

My main problem with this kind of solution to the exercise is that I don’t see how it would work with "In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle” and "Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will work using either representation?” See this post of mine:

https://groups.google.com/g/fallible-ideas/c/ErcZk3tL7BQ/m/Vt77A2sJAgAJ

A less important problem is that the exericse says to "Implement a representation for rectangles in a plane”. I take that to mean they want us to specify where in the plane each rectangle is.

Max Kaye

unread,
Sep 17, 2020, 11:41:37 AM9/17/20
to fallibl...@googlegroups.com
On Mon, 7 Sep 2020 16:34:47 -0400
This is an example of a contract -- a property -- that holds for all inputs. It should be *guarenteed* for any
rectangles with side lengths `a` and `b`.

You could use this example to make sure that certain properties hold (like area and perimeters matching) - useful for
testing software.

Max Kaye

unread,
Sep 17, 2020, 2:57:40 PM9/17/20
to fallibl...@googlegroups.com
On Tue, 8 Sep 2020 17:55:08 +1000
I think I've accidentally sent this again (or maybe it didn't send the
first time). I think it was left in my outbox or drafts or something -
hard to tell, now. In claws-mail the send button is next to the compose
button and I clicked the wrong one.
Reply all
Reply to author
Forward
0 new messages