Difference between revisions of "Thunks and Streams Assignment"
(44 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
=Motivation= | =Motivation= | ||
− | It is all too easy to make a simple mistake on the [[Streams_Assignment Streams Lab]] and have it burn way to much of ones time. We will build some utility functions that will hopefully make our code more clear, as well as raise better errors sooner | + | It is all too easy to make a simple mistake on the [[Streams_Assignment|Streams Lab]] and have it burn way to much of ones time. We will build some utility functions that will hopefully make our code more clear, as well as raise better errors sooner, alerting us if we make a mistake. |
=Code To Use= | =Code To Use= | ||
− | [https://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29 define-syntax] | + | * [https://docs.racket-lang.org/reference/booleans.html #t] true |
− | + | * [https://docs.racket-lang.org/reference/booleans.html #f] false | |
− | [https://docs.racket-lang.org/reference/lambda.html?q=lambda#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29 lambda] | + | * [https://docs.racket-lang.org/reference/define.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._define-syntax%29%29 define-syntax] |
− | + | * [https://docs.racket-lang.org/reference/lambda.html?q=lambda#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._lambda%29%29 lambda] | |
− | [https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28quote._~23~25kernel%29._procedure~3f%29%29 procedure?] | + | * [https://docs.racket-lang.org/reference/procedures.html#%28def._%28%28quote._~23~25kernel%29._procedure~3f%29%29 procedure?] |
− | + | * [https://docs.racket-lang.org/reference/procedures.html?q=procedure-arity#%28def._%28%28quote._~23~25kernel%29._procedure-arity%29%29 procedure-arity] number of arguments a function takes [https://en.wikipedia.org/wiki/Arity Arity on Wikipedia] | |
− | [https://docs.racket-lang.org/reference/procedures.html?q=procedure-arity#%28def._%28%28quote._~23~25kernel%29._procedure-arity%29%29 procedure-arity] | + | * [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._pair~3f%29%29 pair?] |
− | + | * [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._cons%29%29 cons] | |
− | [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._pair~3f%29%29 pair?] | + | * [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._car%29%29 car] |
− | + | * [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._cdr%29%29 cdr] | |
− | [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._cons%29%29 cons] | + | * [https://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29 values] |
− | + | * [https://docs.racket-lang.org/reference/exns.html?q=raise#%28def._%28%28quote._~23~25kernel%29._raise%29%29 raise] | |
− | [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._car%29%29 car] | ||
− | |||
− | [https://docs.racket-lang.org/reference/pairs.html?q=cons#%28def._%28%28quote._~23~25kernel%29._cdr%29%29 cdr] | ||
=Code To Implement= | =Code To Implement= | ||
− | {{RacketToImplement| | + | {{RacketToImplement|uw4|thunk?<br>thunk-that<br>dethunk-that<br>value-next-stream-pair-from-stream<br>stream-cons-ensuring-stream-prime-is-thunk|uw4}} |
==Thunk Utilities== | ==Thunk Utilities== | ||
+ | A [https://en.wikipedia.org/wiki/Thunk thunk] is a 0 argument function. We will write functions to check if an expression is a thunk, a '''MACRO''' to create a thunk from an expression, and a function to evaluate a thunk. | ||
+ | |||
===thunk?=== | ===thunk?=== | ||
− | define a function <code>thunk?</code> which returns | + | define a function <code>thunk?</code> which returns whether the specified parameter is a thunk or not. |
<nowiki>(define (thunk? th) | <nowiki>(define (thunk? th) | ||
Line 29: | Line 28: | ||
===thunk-that=== | ===thunk-that=== | ||
− | define a '''MACRO''' <code>thunk-that</code> which creates thunk | + | define a '''MACRO''' <code>thunk-that</code> which takes a parameter <code>e</code> creates thunk. that is: wraps <code>e</code> in a zero argument function. |
(define-syntax-rule (thunk-that e) | (define-syntax-rule (thunk-that e) | ||
(error 'not-yet-implemented)) | (error 'not-yet-implemented)) | ||
− | ===dethunk=== | + | Thunks are useful for delaying the evaluation of expressions. As such <code>thunk-that</code> must be declared as a macro and not a function. Unlike [https://www.haskell.org/ Haskell] which has lazy evaluation, Racket (and most other languages) [https://en.wikipedia.org/wiki/Eager_evaluation eagerly evaluates] function arguments. |
− | define a function <code>dethunk</code> which takes a thunk parameter <code> | + | |
+ | ===dethunk-that=== | ||
+ | define a function <code>dethunk</code> which takes a thunk parameter <code>e</code> and returns the result of invoking <code>e</code>. | ||
+ | |||
+ | (define (dethunk-that thunk) | ||
+ | (error 'not-yet-implemented)) | ||
+ | |||
+ | If thunking and expression wraps an expression in a single argument function, then de-thunking is simply calling that function. | ||
+ | |||
+ | If the parameter <code>thunk</code> is not a <code>thunk?</code> then <code>dethunk-that</code> should [https://docs.racket-lang.org/reference/exns.html#%28def._%28%28quote._~23~25kernel%29._raise-argument-error%29%29 raise an argument error]. | ||
+ | |||
+ | NOTE: It may seem unnecessary to use <code>dethunk-that</code> when implementing Lab4, when you could simply (thunk)... that is "call the thunk". Still, you are encouraged to use <code>dethunk-that</code> as a bit of verbosity can sometimes help in debugging a sea already full of parentheses. | ||
==Stream Utilities== | ==Stream Utilities== | ||
+ | ===destream=== | ||
+ | define a function <code>destream</code> which takes a <code>stream</code> parameter and evaluates to the resulting dethunked pair. | ||
+ | |||
+ | (define (destream stream) | ||
+ | (error 'not-yet-implemented)) | ||
+ | |||
+ | A critical value of this utility function is to provide early error detection. As such, exceptions should be raised if either | ||
+ | |||
+ | * the parameter <code>stream</code> is not a thunk (this can be handled by <code>dethunk-that</code>) | ||
+ | * the result of de-thunking the <code>stream</code> is not a pair | ||
+ | * next-stream of the pair is not thunk | ||
+ | <!-- | ||
+ | Example use of [https://docs.racket-lang.org/reference/values.html#%28def._%28%28quote._~23~25kernel%29._values%29%29 values] and [https://docs.racket-lang.org/reference/define.html?q=define-values#%28form._%28%28quote._~23~25kernel%29._define-values%29%29 define-values]: | ||
+ | |||
+ | <youtube>iWCcL049dOg</youtube> | ||
+ | |||
+ | <nowiki>(define (div-mod-values n d) | ||
+ | (values (quotient n d) (modulo n d))) | ||
− | + | (define (printf-div-mod-values n d) | |
− | define a | + | (local [(define-values (q r) (div-mod-values n d))] |
+ | (printf "~a/~a => ~a w/ remainder ~a\n" n d q r))) | ||
− | + | (printf-div-mod-values 425 231)</nowiki> | |
− | + | produces the output: | |
− | |||
− | = | + | <nowiki>425/231 => 1 w/ remainder 194</nowiki> |
− | + | --> | |
− | ===stream- | + | ===stream-cons-ensuring-stream-prime-is-thunk=== |
− | + | Define a function <code>cons-with-thunk-check-on-next-stream</code> which takes two parameters <code>value</code> and <code>next-stream</code>. | |
− | define | + | ((define (cons-with-thunk-check-on-next-stream element next-stream) |
+ | (error 'not-yet-implemented)) | ||
− | + | If the specified <code>next-stream</code> parameter is not a thunk then an error should be raised: | |
− | |||
− | <code>(raise | + | <code>(raise-argument-error "next-stream" "thunk?" next-stream)</code> |
− | If <code>stream | + | Do '''NOT''' create a thunk. If <code>next-stream</code> is a thunk it should simply [https://docs.racket-lang.org/reference/pairs.html#%28def._%28%28quote._~23~25kernel%29._cons%29%29 cons] <code>value</code> and <code>next-stream</code>. |
− | + | =Test= | |
+ | ==thunk== | ||
+ | {{RacketUnitTest|thunk_test|uw4}} | ||
− | == | + | ==stream== |
− | + | {{RacketUnitTest|stream_test|uw4}} | |
− |
Revision as of 21:06, 27 October 2022
Contents
Motivation
It is all too easy to make a simple mistake on the Streams Lab and have it burn way to much of ones time. We will build some utility functions that will hopefully make our code more clear, as well as raise better errors sooner, alerting us if we make a mistake.
Code To Use
- #t true
- #f false
- define-syntax
- lambda
- procedure?
- procedure-arity number of arguments a function takes Arity on Wikipedia
- pair?
- cons
- car
- cdr
- values
- raise
Code To Implement
file: | src/main/racket/uw4/uw4.rkt | |
functions: | thunk? thunk-that dethunk-that value-next-stream-pair-from-stream stream-cons-ensuring-stream-prime-is-thunk |
Thunk Utilities
A thunk is a 0 argument function. We will write functions to check if an expression is a thunk, a MACRO to create a thunk from an expression, and a function to evaluate a thunk.
thunk?
define a function thunk?
which returns whether the specified parameter is a thunk or not.
(define (thunk? th) (error 'not-yet-implemented))
thunk-that
define a MACRO thunk-that
which takes a parameter e
creates thunk. that is: wraps e
in a zero argument function.
(define-syntax-rule (thunk-that e) (error 'not-yet-implemented))
Thunks are useful for delaying the evaluation of expressions. As such thunk-that
must be declared as a macro and not a function. Unlike Haskell which has lazy evaluation, Racket (and most other languages) eagerly evaluates function arguments.
dethunk-that
define a function dethunk
which takes a thunk parameter e
and returns the result of invoking e
.
(define (dethunk-that thunk) (error 'not-yet-implemented))
If thunking and expression wraps an expression in a single argument function, then de-thunking is simply calling that function.
If the parameter thunk
is not a thunk?
then dethunk-that
should raise an argument error.
NOTE: It may seem unnecessary to use dethunk-that
when implementing Lab4, when you could simply (thunk)... that is "call the thunk". Still, you are encouraged to use dethunk-that
as a bit of verbosity can sometimes help in debugging a sea already full of parentheses.
Stream Utilities
destream
define a function destream
which takes a stream
parameter and evaluates to the resulting dethunked pair.
(define (destream stream) (error 'not-yet-implemented))
A critical value of this utility function is to provide early error detection. As such, exceptions should be raised if either
- the parameter
stream
is not a thunk (this can be handled bydethunk-that
) - the result of de-thunking the
stream
is not a pair - next-stream of the pair is not thunk
stream-cons-ensuring-stream-prime-is-thunk
Define a function cons-with-thunk-check-on-next-stream
which takes two parameters value
and next-stream
.
((define (cons-with-thunk-check-on-next-stream element next-stream) (error 'not-yet-implemented))
If the specified next-stream
parameter is not a thunk then an error should be raised:
(raise-argument-error "next-stream" "thunk?" next-stream)
Do NOT create a thunk. If next-stream
is a thunk it should simply cons value
and next-stream
.
Test
thunk
file: | thunk_test.rkt | Test |
source folder: | src/test/racket/uw4 |
note: ensure that you have removed all printing to receive credit for any assignment.
stream
file: | stream_test.rkt | Test |
source folder: | src/test/racket/uw4 |
note: ensure that you have removed all printing to receive credit for any assignment.