Just another update
This commit is contained in:
parent
a25938f123
commit
00a190b0a6
6591 changed files with 94363 additions and 23227 deletions
|
|
@ -1,4 +1,14 @@
|
|||
{{omit from|BBC BASIC}}
|
||||
'''Constrained genericity''' or '''bounded quantification''' means that a parametrized type or function (see [[parametric polymorphism]]) can only be instantiated on types fulfilling some conditions, even if those conditions are not used in that function.
|
||||
'''Constrained genericity''' or '''bounded quantification''' means
|
||||
that a parametrized type or function (see [[parametric polymorphism]])
|
||||
can only be instantiated on types fulfilling some conditions,
|
||||
even if those conditions are not used in that function.
|
||||
|
||||
Say a type is called "eatable" if you can call the function <tt>eat</tt> on it. Write a generic type <tt>FoodBox</tt> which contains a collection of objects of a type given as parameter, but can only be instantiated on eatable types. The FoodBox shall not use the function eat in any way (i.e. without the explicit restriction, it could be instantiated on any type). The specification of a type being eatable should be as generic as possible in your language (i.e. the restrictions on the implementation of eatable types should be as minimal as possible). Also explain the restrictions, if any, on the implementation of eatable types, and show at least one example of an eatable type.
|
||||
Say a type is called "eatable" if you can call the function <tt>eat</tt> on it.
|
||||
Write a generic type <tt>FoodBox</tt> which contains a collection of objects of
|
||||
a type given as parameter, but can only be instantiated on eatable types.
|
||||
The FoodBox shall not use the function eat in any way (i.e. without the explicit restriction, it could be instantiated on any type).
|
||||
The specification of a type being eatable should be as generic as possible
|
||||
in your language (i.e. the restrictions on the implementation of eatable types
|
||||
should be as minimal as possible).
|
||||
Also explain the restrictions, if any, on the implementation of eatable types,
|
||||
and show at least one example of an eatable type.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
#lang racket
|
||||
(module+ test (require tests/eli-tester))
|
||||
|
||||
;; This is all that an object should need to properly implement.
|
||||
(define edible<%>
|
||||
(interface () [eat (->m void?)]))
|
||||
|
||||
(define (generic-container<%> containee/c)
|
||||
(interface ()
|
||||
[contents (->m (listof containee/c))]
|
||||
[insert (->m containee/c void?)]
|
||||
[remove-at (->m exact-nonnegative-integer? containee/c)]
|
||||
[count (->m exact-nonnegative-integer?)]))
|
||||
|
||||
(define ((generic-box-mixin containee/c) %)
|
||||
(->i ([containee/c contract?])
|
||||
(rv (containee/c) (implementation?/c (generic-container<%> containee/c))))
|
||||
(class* % ((generic-container<%> containee/c))
|
||||
(super-new)
|
||||
(define l empty)
|
||||
(define/public (contents) l)
|
||||
(define/public (insert o) (set! l (cons o l)))
|
||||
(define/public (remove-at i)
|
||||
(begin0 (list-ref l i)
|
||||
(append (take l i) (drop l (add1 i)))))
|
||||
(define/public (count) (length l))))
|
||||
|
||||
;; As I understand it, a "Food Box" from the task is still a generic... i.e.
|
||||
;; you will specify it down ;; to an "apple-box%" so: food-box%-generic is still
|
||||
;; generic. food-box% will take any kind of food.
|
||||
(define/contract (food-box-mixin T%)
|
||||
(-> (or/c (λ (i) (eq? edible<%> i)) (implementation?/c edible<%>))
|
||||
(make-mixin-contract))
|
||||
(generic-box-mixin (and/c (is-a?/c edible<%>) (is-a?/c T%))))
|
||||
|
||||
(module+ test
|
||||
|
||||
(define integer-box% ((generic-box-mixin integer?) object%))
|
||||
(define integer-box (new integer-box%))
|
||||
|
||||
(define apple%
|
||||
(class* object% (edible<%>)
|
||||
(super-new)
|
||||
(define/public (eat)
|
||||
(displayln "nom!"))))
|
||||
|
||||
(define banana%
|
||||
(class* object% (edible<%>)
|
||||
(super-new)
|
||||
(define/public (eat)
|
||||
(displayln "peel.. peel... nom... nom!"))))
|
||||
|
||||
(define semolina%
|
||||
(class* object% () ; <-- empty interfaces clause
|
||||
(super-new)
|
||||
;; you can call eat on it... but it's not explicitly (or even vaguely)
|
||||
;; edible<%>
|
||||
(define/public (eat) (displayln "blech!"))))
|
||||
|
||||
;; this will take any object that is edible<%> and edible<%> (therefore all
|
||||
;; edible<%> objects)
|
||||
(define any-food-box (new ((food-box-mixin edible<%>) object%)))
|
||||
|
||||
;; this will take any object that is edible and an apple<%>
|
||||
;; (therefore only apple<%>s)
|
||||
(define apple-food-box (new ((food-box-mixin apple%) object%)))
|
||||
|
||||
(test
|
||||
;; Test generic boxes
|
||||
(send integer-box insert 22)
|
||||
(send integer-box insert "a string") =error> exn:fail:contract?
|
||||
|
||||
;; Test the food box that takes any edible<%>
|
||||
(send any-food-box insert (new apple%))
|
||||
(send any-food-box insert (new banana%))
|
||||
(send any-food-box insert (new semolina%)) =error> exn:fail:contract?
|
||||
|
||||
;; Test the food box that takes any apple%
|
||||
(send apple-food-box insert (new apple%))
|
||||
(send apple-food-box insert (new banana%)) =error> exn:fail:contract?
|
||||
(send apple-food-box insert (new semolina%)) =error> exn:fail:contract?
|
||||
(send apple-food-box count) => 1
|
||||
|
||||
;; Show that you cannot make a food-box from the non-edible<%> semolina cannot
|
||||
(implementation? semolina% edible<%>) => #f
|
||||
(new ((food-box-mixin semolina%) object%)) =error> exn:fail:contract?))
|
||||
Loading…
Add table
Add a link
Reference in a new issue