Cantor set: Difference between revisions
→JavaScript :: Dual representation: Updated primitives, tidied.
(→JavaScript :: Dual representation: Updated primitives, tidied.) |
|||
Line 1,792:
<lang javascript>(() => {
// --------------------- CANTOR ----------------------
// cantor :: [(Rational, Rational)] ->
// [(Rational, Rational)]
const cantor = xs => {
const go =
const [r1, r2] =
const third = ratioDiv(ratioMinus(r2
return [
Tuple(r1
Tuple(ratioMinus(r2
];
};
return xs.flatMap(go);
};
// ---------------------- TEST -----------------------
// main :: IO ()
const main = () => {
const
xs = take(4)(
iterate(cantor)([Tuple(0)(1)])
);
return [
`${unlines(xs.map(intervalRatios))}\n`,
intervalBars(xs)
]
.join("\n\n");
};
// --------------------- DISPLAY ---------------------
// intervalRatios :: [(Rational, Rational)] -> String
const intervalRatios = xs => {
const go = tpl =>
)
return `(${xs.map(go).join(") (")})`;
};
// intervalBars :: [[(Rational, Rational)]] -> String
const intervalBars =
const go = w => xs =>
const [wx, wy] = Array.from(tpl).map(
r => ratioMult(w
)
);
return
replicateString(
)(" ") + replicateString(
floor(ratioMinus(wy)(wx))
)("█")
);
}
const d =
return unlines(rs.map(
go(Ratio(d)(1))
));
};
//
// Ratio :: Integral a => a -> a -> Ratio a
const Ratio = a => b => {
const go = (x, y) =>
0 !== y ? (() => {
const d = gcd(x)(y);
return {
type: "Ratio",
// numerator
"n": Math.trunc(x / d),
// denominator
"d": Math.trunc(y / d)
};
})() : undefined;
return go(a * signum(b), abs(b));
};
// Tuple (,) :: a -> b -> (a, b)
const Tuple =
length: 2
});
// abs :: Num -> Num
const abs =
// Absolute value of a given number
// without the sign.
x => 0 > x ? (
-x
) : x;
//
return _gcd(Math.abs(x), Math.abs(y));
},
c = gcde(Boolean(eps) ? (
eps
) : (1 / 10000), 1, n);
return Ratio(
Math.floor(n / c)
)(
Math.floor(1 / c)
);
};
// floor :: Num -> Int
Line 1,885 ⟶ 1,940:
const
nr = (
properFraction
) : properFracRatio
)(x),
n = nr[0];
return 0 > nr[1] ? n - 1 : n;
};
// fst :: (a, b) -> a
const fst = tpl =>
// First member of a pair.
tpl[0];
// gcd :: Integral a => a -> a -> a
const gcd = x =>
y => {
const zero = x.constructor(0);
const go = (a, b) =>
zero === b ? (
a
) : go(b, a % b);
return go(abs(x), abs(y));
};
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);
// iterate :: (a -> a) -> a -> Gen [a]
function*
let v =
while (true) {
yield v;
v = f(v);
}
};
// last :: [a] -> a
const last = xs =>
0 < xs.length ? (
xs.slice(-1)[0]
) : null;
// lcm :: Int -> Int -> Int
const lcm =
// The smallest positive integer divisible
// without remainder by both x and y.
y => (x === 0 || y === 0) ? (
0
) : Math.abs(Math.floor(x / gcd(x)(y)) * y);
//
// acc -> [x] -> (acc, [y])
const mapAccumL = f =>
// A tuple of an accumulation and a list
// obtained by a combined map and fold,
// with accumulation from left to right.
acc => xs => [...xs].reduce(
(a, x) => {
const tpl = f(a[0])(x);
return [tpl[0], a[1].concat(tpl[1])];
},
[acc, []]
);
// maximum :: Ord a => [a] -> a
const maximum = xs => (
(a, y) => y > a ? (
y
) : a, ys[0]
)
) : undefined
)(xs);
// properFracRatio :: Ratio -> (Int, Ratio)
const properFracRatio = nd => {
const [q, r] = Array.from(quotRem(nd.n
return Tuple(q)(Ratio(r)(nd.d));
};
// properFraction :: Real -> (Int, Real)
const properFraction = n => {
const i = Math.floor(n) + (n < 0 ? 1 : 0);
return Tuple(i)(n - i);
};
// quotRem ::
const quotRem =
// The quotient, tupled with the remainder.
n => Tuple(
Math.trunc(m / n)
)(
m % n
);
// ratioDiv :: Rational -> Rational -> Rational
const ratioDiv =
const [r1, r2] =
return Ratio(r1.n * r2.d)(
r1.d * r2.n
);
};
// ratioMinus :: Rational -> Rational -> Rational
const ratioMinus =
const [r1, r2] =
const d = lcm(r1.d
return Ratio(
(r1.n * (d / r1.d)) - (r2.n * (d / r2.d))
)(d);
};
// ratioMult :: Rational -> Rational -> Rational
const ratioMult =
const [r1, r2] =
return Ratio(r1.n * r2.n)(
);
};
// ratioPlus :: Rational -> Rational -> Rational
const ratioPlus = n1 =>
n2 => {
const [r1, r2] = [n1, n2].map(rational);
const d = lcm(r1.d)(r2.d);
return Ratio(
(r1.n * (d / r1.d)) + (
r2.n * (d / r2.d)
)
)(d);
};
// rational :: Num a => a -> Rational
const rational = x =>
isNaN(x) ? x :
Ratio(x)(1)
) : approxRatio(undefined)(x);
// replicateString :: Int -> String -> String
const replicateString =
s => s.repeat(n);
// showRatio :: Ratio -> String
const showRatio = r =>
r.toString()
) : r.n.toString() + (
1 !== r.d ? (
) :
);
// signum :: Num -> Num
const signum = n =>
// | Sign of a number.
n.constructor(
0 > n ? (
-1
) : (
0 < n ? 1 : 0
)
);
// snd :: (a, b) -> b
const snd = tpl =>
// Second member of a pair.
tpl[1];
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take =
// The first n elements of a list,
// string of characters, or stream.
xs => "GeneratorFunction" !== xs
.constructor.constructor.name ? (
xs.slice(0, n)
) : [].concat
length: n
}, () => {
const x = xs.next();
return x.done ? [] : [x.value];
}));
// unlines :: [String] -> String
const unlines = xs =>
// A single string formed by the intercalation
// of a list of strings with the newline character.
xs.join("\n");
// MAIN ---
|