Jump to content

Generator/Exponential: Difference between revisions

→‎{{header|JavaScript}}: Added a functional version, showing compositional derivation of custom generators.
(→‎{{header|Python}}: (Compositional version) retired fmapGen for vanilla `map` (which works over generators))
(→‎{{header|JavaScript}}: Added a functional version, showing compositional derivation of custom generators.)
Line 1,558:
 
=={{header|JavaScript}}==
===Procedural===
{{works with|Firefox 3.6 using JavaScript 1.7|}}
 
Line 1,600 ⟶ 1,601:
</lang>
 
====ES6====
<lang JavaScript>function* nPowerGen(n) {
let e = 0;
Line 1,635 ⟶ 1,636:
1024
1089</pre>
 
===Functional===
 
Compositional derivation of custom generators:
{{Works with|JavaScript|ES6}}
<lang javascript>(() => {
'use strict';
 
// main :: IO()
const main = () => {
 
// powers :: Gen [Int]
const powers = n =>
fmapGen(
x => Math.pow(x, n),
enumFrom(0)
);
 
// xs :: [Int]
const xs = take(10, drop(20,
differenceGen(
powers(2),
powers(3)
)
));
 
console.log(xs);
// -> [529,576,625,676,784,841,900,961,1024,1089]
};
 
 
// GENERIC FUNCTIONS ----------------------------------
 
// Just :: a -> Maybe a
const Just = x => ({
type: 'Maybe',
Nothing: false,
Just: x
});
 
// Nothing :: Maybe a
const Nothing = () => ({
type: 'Maybe',
Nothing: true,
});
 
// Tuple (,) :: a -> b -> (a, b)
const Tuple = (a, b) => ({
type: 'Tuple',
'0': a,
'1': b,
length: 2
});
 
// differenceGen :: Gen [a] -> Gen [a] -> Gen [a]
function* differenceGen(ga, gb) {
// All values of generator stream a except any
// already seen in generator stream b.
const
stream = zipGen(ga, gb),
sb = new Set([]);
while (true) {
const xy = take(1, stream);
if (0 < xy.length) {
const [x, y] = Array.from(xy[0]);
sb.add(y);
if (!sb.has(x)) yield x
}
}
};
 
// drop :: Int -> [a] -> [a]
// drop :: Int -> Generator [a] -> Generator [a]
// drop :: Int -> String -> String
const drop = (n, xs) =>
Infinity > length(xs) ? (
xs.slice(n)
) : (take(n, xs), xs);
 
// enumFrom :: Enum a => a -> [a]
function* enumFrom(x) {
let v = x;
while (true) {
yield v;
v = 1 + v;
}
}
 
// fmapGen <$> :: (a -> b) -> Gen [a] -> Gen [b]
function* fmapGen(f, gen) {
let v = take(1, gen);
while (0 < v.length) {
yield(f(v[0]))
v = take(1, gen)
}
}
 
// fst :: (a, b) -> a
const fst = tpl => tpl[0];
 
// Returns Infinity over objects without finite length.
// This enables zip and zipWith to choose the shorter
// argument when one is non-finite, like cycle, repeat etc
 
// length :: [a] -> Int
const length = xs =>
(Array.isArray(xs) || 'string' === typeof xs) ? (
xs.length
) : Infinity;
 
// snd :: (a, b) -> b
const snd = tpl => tpl[1];
 
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take = (n, xs) =>
'GeneratorFunction' !== xs.constructor.constructor.name ? (
xs.slice(0, n)
) : [].concat.apply([], Array.from({
length: n
}, () => {
const x = xs.next();
return x.done ? [] : [x.value];
}));
 
// uncons :: [a] -> Maybe (a, [a])
const uncons = xs => {
const lng = length(xs);
return (0 < lng) ? (
lng < Infinity ? (
Just(Tuple(xs[0], xs.slice(1))) // Finite list
) : (() => {
const nxt = take(1, xs);
return 0 < nxt.length ? (
Just(Tuple(nxt[0], xs))
) : Nothing();
})() // Lazy generator
) : Nothing();
};
 
// zipGen :: Gen [a] -> Gen [b] -> Gen [(a, b)]
const zipGen = (ga, gb) => {
function* go(ma, mb) {
let
a = ma,
b = mb;
while (!a.Nothing && !b.Nothing) {
let
ta = a.Just,
tb = b.Just
yield(Tuple(fst(ta), fst(tb)));
a = uncons(snd(ta));
b = uncons(snd(tb));
}
}
return go(uncons(ga), uncons(gb));
};
 
// MAIN ---
return main();
})();</lang>
{{Out}}
<pre>[529,576,625,676,784,841,900,961,1024,1089]</pre>
 
=={{header|jq}}==
9,655

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.