patternMinor
Converting English Measurements to Metric and vice versa
Viewed 0 times
viceenglishversametricmeasurementsandconverting
Problem
I finished answering Exercise 3.3.1 of How to Design Programs where:
Exercise 3.3.1. The United States uses the English system of
(length) measurements. The rest of the world uses the metric system.
So, people who travel abroad and companies that trade with foreign
partners often need to convert English measurements to metric ones and
vice versa.
The code is also located in here.
```
;; Contract: print : expr expected_expr ->
;;expr "should be" expected_expr
;; Purpose: to test expressions to find out whether they're
;; correct or not
;; Examples: (print (inches->cm 22/7) 7.98287514)
;; => "3.142857142857143 should be 7.98287514"
;; Definition: [refines the header]
(define (print actual expected)
(string-append
(number->string (exact->inexact actual))
" should be "
(number->string (exact->inexact expected))))
;; Contract: inches->cm : number -> number
;; Purpose: to convert inches to centimeters
;; Examples: (inches->cm 22/7) should be 7.9828514
;; Definition: [refines the header]
(define (inches->cm in)
(* in 2.54))
;; Tests:
(print (inches->cm 22/7) (* 2.54 (/ 22 7)))
(print (inches->cm 3.5) (* 2.54 3.50))
(print (inches->cm 100) (* 2.54 100))
;; Contract: feet->inches : number -> number
;; Purpose: to convert feet to inches
;; Examples: (feet->inches 32) should be 384
;; Definition:
(define (feet->inches ft)
(* ft 12))
;; Tests:
(print (feet->inches 32) (* 32 12))
(print (feet->inches 12.5) (* 12.5 12))
(print (feet->inches -99) (* -99 12))
;; Contract: yards->feet : number -> number
;; Purpose: to convert yards to feet
;; Examples: (yards->feet 3) should be 9
;; Definition:
(define (yards->feet yd)
(* yd 3))
;; Tests:
(print (yards->feet 3) (* 3 3))
(print (yards->feet 1.5) (* 1.5 3))
(print (yards->feet -3.5) (* -3.5 3))
;; Contract: rods->yards : number -> number
;; Purpose: to convert rods to yards
;; Examples: (rods->yards 1) should be 5.5
;; Definition:
(define (rods->yards rd)
(* rd 5.5))
Exercise 3.3.1. The United States uses the English system of
(length) measurements. The rest of the world uses the metric system.
So, people who travel abroad and companies that trade with foreign
partners often need to convert English measurements to metric ones and
vice versa.
The code is also located in here.
```
;; Contract: print : expr expected_expr ->
;;expr "should be" expected_expr
;; Purpose: to test expressions to find out whether they're
;; correct or not
;; Examples: (print (inches->cm 22/7) 7.98287514)
;; => "3.142857142857143 should be 7.98287514"
;; Definition: [refines the header]
(define (print actual expected)
(string-append
(number->string (exact->inexact actual))
" should be "
(number->string (exact->inexact expected))))
;; Contract: inches->cm : number -> number
;; Purpose: to convert inches to centimeters
;; Examples: (inches->cm 22/7) should be 7.9828514
;; Definition: [refines the header]
(define (inches->cm in)
(* in 2.54))
;; Tests:
(print (inches->cm 22/7) (* 2.54 (/ 22 7)))
(print (inches->cm 3.5) (* 2.54 3.50))
(print (inches->cm 100) (* 2.54 100))
;; Contract: feet->inches : number -> number
;; Purpose: to convert feet to inches
;; Examples: (feet->inches 32) should be 384
;; Definition:
(define (feet->inches ft)
(* ft 12))
;; Tests:
(print (feet->inches 32) (* 32 12))
(print (feet->inches 12.5) (* 12.5 12))
(print (feet->inches -99) (* -99 12))
;; Contract: yards->feet : number -> number
;; Purpose: to convert yards to feet
;; Examples: (yards->feet 3) should be 9
;; Definition:
(define (yards->feet yd)
(* yd 3))
;; Tests:
(print (yards->feet 3) (* 3 3))
(print (yards->feet 1.5) (* 1.5 3))
(print (yards->feet -3.5) (* -3.5 3))
;; Contract: rods->yards : number -> number
;; Purpose: to convert rods to yards
;; Examples: (rods->yards 1) should be 5.5
;; Definition:
(define (rods->yards rd)
(* rd 5.5))
Solution
I see a few points that seem open to improvement.
First of all, in some cases you document the "contract" based on the type of the input and output ("number -> number") but in others the unit of measure ("Miles -> furlongs").
The units of measure are already documented directly in the function's name, so the type is the only one that really makes much sense to document in comments. For that, you'd probably be better off with a single header documenting the contract for all the functions.
Second, essentially all of these are really just multiplying/dividing the input by a factor, and returning the result. As such, it would probably make more sense to pass the units to convert as parameters. Then you'd have a single function that looked up the correct factor from a table and returned the result based on that.
Third, I'd rather see a function that actually compared results and told me whether the test passed or failed. As it stands now, I'm left to scan through the results myself to see whether the functions worked correctly or not.
Finally, the units you've chosen to support seem rather strange, at least to me. "rods" are used almost exclusively in surveying, and furlongs are used almost exclusively in stories about medieval times. At the same time, although the initial discussion is about converting between Imperial and metric measures, the only metric unit you seem to support is the centimeter, not such common measures as meters or kilometers.
P.S. The basic premise in the exercise is also somewhat incorrect: not all the rest of the world uses the metric system. For example, Imperial measures are still used quite a bit in the UK, and in some other former UK colonies as well.
First of all, in some cases you document the "contract" based on the type of the input and output ("number -> number") but in others the unit of measure ("Miles -> furlongs").
The units of measure are already documented directly in the function's name, so the type is the only one that really makes much sense to document in comments. For that, you'd probably be better off with a single header documenting the contract for all the functions.
Second, essentially all of these are really just multiplying/dividing the input by a factor, and returning the result. As such, it would probably make more sense to pass the units to convert as parameters. Then you'd have a single function that looked up the correct factor from a table and returned the result based on that.
Third, I'd rather see a function that actually compared results and told me whether the test passed or failed. As it stands now, I'm left to scan through the results myself to see whether the functions worked correctly or not.
Finally, the units you've chosen to support seem rather strange, at least to me. "rods" are used almost exclusively in surveying, and furlongs are used almost exclusively in stories about medieval times. At the same time, although the initial discussion is about converting between Imperial and metric measures, the only metric unit you seem to support is the centimeter, not such common measures as meters or kilometers.
P.S. The basic premise in the exercise is also somewhat incorrect: not all the rest of the world uses the metric system. For example, Imperial measures are still used quite a bit in the UK, and in some other former UK colonies as well.
Context
StackExchange Code Review Q#58805, answer score: 2
Revisions (0)
No revisions yet.