| CS 330 | Home | Schedule | Resources |
Estimated time: 4 hours
Acceptance tests for HW 9.
About acceptance tests, for anyone who missed it before.
Objective: practice higher-order programming techniques
declare
fun {BrowseVal X} {Browse X} X end
F= fun {$ X}
fun {$ Y} {Y X} end
end
G= {F [1 2 3 4 5]}
{Every L F} that takes a list and a function as input, and returns true if every element of the list has the property represented by the function argument. For example, {Every [foo 0 4 8 0 2 6] IsInt} should return false. Write Every so that it will stop processing the rest of the list if the answer can be determined before the whole list has been processed.
{Test F L} that takes a function or procedure as input and a list of input/output pairs, and checks whether the actual output matches the test case output when given the corresponding input. Test should return a boolean value indicating whether all the tests succeeded. You can do this using Procedure.apply (see the Mozart
documentation). Create 3 of your OWN test cases for the Every function, and use Test to make sure everything works properly. Then, try your Test code on the built-in functions All and Some as well, using the same test cases. You will need to copy your test cases using the Copy function shown below before each run of Test. For full credit, submit the code you wrote and executed, as well as its output. See problem 5 below for examples that may be helpful.
fun {Copy R}
if {Not {IsDet R}} then X in X
elseif {Not {IsRecord R}} then R
else {Record.map R Copy}
end
end
[Let me rephrase that: Test takes a list of input/output pairs, where both elements of a pair are a list of parameters. {Procedure.apply Number.'+' [4 5 A]} is the same as {Number.'+' 4 5 A} which is the same as A={Number.'+' 4 5}. So if we were testing Number.'+' we might have a pair [4 5 _]#[4 5 9] to specify that the third parameter is unbound before and equals 9 afterward. (That's why you need "Copy", because you don't want to bind the variable in the test case, just a copy of it.) If that's still unclear, and it might be, either examine the acceptance tests for examples or else call me on my cell. -Max]
{TestGen Fs} that takes as input a list of unary functions returning true or false (i.e. predicates) and returns a one-parameter function that will apply the predicates to any input, and return true if and only if all predicates are true for that input. Bind the returned function to a variable named Tester, and execute it. For full credit, submit the code you wrote and executed.[Use short-circuiting logic in the style of andthen and orelse--don't test more predicates than you need to to get the answer. -Max]
declare
% three example predicates
Predicates = [IsProcedure % is the input a function?
fun {$ P} {ProcedureArity P}==3 end % does it take
% three parameters?
fun {$ P} {Test P Cases} end] % does it pass the test cases?
Cases=[ [[foo 2 3] IsInt _]#[[foo 2 3] IsInt false]
[[49 0 23] IsInt _]#[[49 0 23] IsInt true]
[[foo bar baz] IsAtom _]#[[foo bar baz] IsAtom true]]
Tester=
{TestGen Predicates}
Note that one of the predicates uses the Test function you wrote for problem #3. Don't get Test mixed up with TestGen. Test tests a set of input-output pairs of a function, whereas TestGen (in this case) makes a function "Tester" which does... what? (Don't answer that for credit, but make sure you understand.)
[Another point of clarification: Tester will behave differently depending upon the predicates you pass in. The acceptance tests are written with the above code in mind (Tester={TestGen Predicates}). For credit, you can either use the above Tester or write your own predicates, but if you do the latter you'll fail the tests for 5a. That's okay and expected. Hope that helps. -Max]