RosettaCodeData/Task/Convert-decimal-number-to-rational/AppleScript/convert-decimal-number-to-rational.applescript
2019-09-12 10:33:56 -07:00

91 lines
1.8 KiB
AppleScript

on run
script ratioString
-- Using a tolerance epsilon of 1/10000
on |λ|(x)
showRatio(approxRatio(1.0E-4, x))
end |λ|
end script
map(ratioString, ¬
{0.9054054, 0.518518, 0.75})
--> {"67/74", "14/27", "3/4"}
end run
-- approxRatio :: Real -> Real -> Ratio
on approxRatio(epsilon, n)
if {real, integer} contains (class of epsilon) and 0 < epsilon then
set e to epsilon
else
set e to 1 / 10000
end if
script gcde
on |λ|(e, x, y)
script _gcd
on |λ|(a, b)
if b < e then
a
else
|λ|(b, a mod b)
end if
end |λ|
end script
|λ|(abs(x), abs(y)) of _gcd
end |λ|
end script
set c to |λ|(e, 1, n) of gcde
Ratio((n div c), (1 div c))
end approxRatio
-- Ratio :: Int -> Int -> Ratio
on Ratio(n, d)
{type:"Ratio", n:n, d:d}
end Ratio
-- showRatio :: Ratio -> String
on showRatio(r)
(n of r as string) & "/" & (d of r as string)
end showRatio
-- GENERIC FUNCTIONS ---------------------------------------------
-- abs :: Num -> Num
on abs(x)
if 0 > x then
-x
else
x
end if
end abs
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map