--[[ Rational Arithmetic Data Representation Module (Closure) H. Conrad Cunningham, Professor Computer and Information Science University of Mississippi Developed for CSci 450/503, Organization of Programming Languages, Fall 2016 This version of the data representation module uses a closure instead of an array to represent a rational number but defers computing the GCD until numer or denom is called. 1234567890123456789012345678901234567890123456789012345678901234567890 2016-09-11: Adapted from Lua modules rationalCore & rationalDeferGCD 2016-09-14: Removed misleading Haskell code This is a new Lua version. It benefits from from section 2.1 and other sections of Abelson and Sussman's _Structure and Interpretation of Computer Programs_ (http://mitpress.mit.edu/sicp/). --]] -- UTILITY FUNCTIONS (not exported) -- Assumes n is numeric local function signum(n) if n == 0 then return 0 elseif n > 0 then return 1 else return -1 end end -- Assumes arguments are integers local function gcd(x,y) local function gcdaux(x,y) if y == 0 then return x else return gcdaux(y, x % y) -- tail recursive end end return gcdaux(math.abs(x), math.abs(y)) end -- RATIONAL ARITHMETIC OPERATORS -- Creates a new rational number, but does not -- check whether x and y are integers and y nonzero local function newRat(x,y) if x == 0 then return function() return 0, 1 end else return -- return thunk (closure) function() local xx = signum(y) * x local yy = math.abs(y) local d = gcd(xx,yy) return xx/d, yy/d end end end -- Checks whether arguments are integers in Lua <= 5.2 local function makeRat(x,y) if type(x) == "number" and type(y) == "number" and x == math.floor(x) and y == math.floor(y) and y ~= 0 then return newRat(x,y) else error("Cannot construct rational number " .. tostring(x) .. "/" .. tostring(y) ) end end -- Assumes r is created by makeRat local function numer(r) local x, _ = r() -- force thunk (closure) return x end -- Assumes r is created by makeRat local function denom(r) local _, y = r() -- force thunk (closure) return y end -- Should newRat also be exported? return { makeRat = makeRat, numer = numer, denom = denom }