Fractran: Difference between revisions

Content added Content deleted
m (→‎Haskell - Generation of primes: Simplified slightly by replacing findIndex with elemIndex)
(→‎{{header|JavaScript}}: Added a functionally composed version, attempting primes, but lacking bigInt)
Line 1,902: Line 1,902:


=={{header|JavaScript}}==
=={{header|JavaScript}}==
===Imperative===
<lang javascript>
// Parses the input string for the numerators and denominators
<lang javascript>// Parses the input string for the numerators and denominators
function compile(prog, numArr, denArr) {
function compile(prog, numArr, denArr) {
let regex = /\s*(\d*)\s*\/\s*(\d*)\s*(.*)/m;
let regex = /\s*(\d*)\s*\/\s*(\d*)\s*(.*)/m;
Line 1,947: Line 1,947:
let [num, den] = compile("17/91 78/85 19/51 23/38 29/33 77/29 95/23 77/19 1/17 11/13 13/11 15/14 15/2 55/1", [], []);
let [num, den] = compile("17/91 78/85 19/51 23/38 29/33 77/29 95/23 77/19 1/17 11/13 13/11 15/14 15/2 55/1", [], []);
body.innerHTML = dump(num, den);
body.innerHTML = dump(num, den);
body.innerHTML += exec(2, 0, 15, num, den);
body.innerHTML += exec(2, 0, 15, num, den);</lang>

</lang>
===Functional===
{{Trans|Haskell}}

Here is a functionally composed version, which also derives a few primes. I may have missed something, but this first draft suggests that we may need bigInt support (which JS lacks) to get as far as the sixth prime.
<lang javascript>(() => {
'use strict';

// fractran :: [Ratio Int] -> Int -> Gen [Int]
const fractran = (xs, n) => {
function* go(n) {
let
v = n,
mb = find(r => 0 === v % r.d, xs);
yield v
while (!mb.Nothing) {
mb = bindMay(
find(r => 0 === v % r.d, xs),
r => (
v = truncate({
type: 'Ratio',
n: v * r.n,
d: r.d
}),
Just(v)
)
);
mb.Just && (yield v)
}
};
return go(n);
};

// readRatios :: String -> [Ratio]
const readRatios = s =>
map(x => ratio(...map(read, splitOn('/', x))),
splitOn(',', s)
);

// main :: IO()
const main = () => {

// strRatios :: String
const strRatios = `17/91, 78/85, 19/51, 23/38, 29/33, 77/29,
95/23 , 77/19, 1/17, 11/13, 13/11, 15/14, 15/2, 55/1`;

showLog(
'First fifteen steps:',
take(15,
fractran(readRatios(strRatios), 2)
)
);

showLog(
'First five primes:',
take(5,
mapMaybeGen(
x => fmapMay(
succ,
elemIndex(
2,
takeWhileGen(
even,
iterate(n => div(n, 2), x)
)
)
),
fractran(readRatios(strRatios), 2)
)
)
);
};

// GENERIC ABSTRACTIONS ----------------------------

// 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
});

// | Absolute value.

// abs :: Num -> Num
const abs = Math.abs;

// bindMay (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
const bindMay = (mb, mf) =>
mb.Nothing ? mb : mf(mb.Just);

// chr :: Int -> Char
const chr = String.fromCodePoint;

// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = (f, xs) =>
xs.reduce((a, x) => a.concat(f(x)), []);

// div :: Int -> Int -> Int
const div = (x, y) => Math.floor(x / y);

// elemIndex :: Eq a => a -> [a] -> Maybe Int
const elemIndex = (x, xs) => {
const i = xs.indexOf(x);
return -1 === i ? (
Nothing()
) : Just(i);
};

// even :: Int -> Bool
const even = n => 0 === n % 2;

// find :: (a -> Bool) -> [a] -> Maybe a
const find = (p, xs) => {
for (let i = 0, lng = xs.length; i < lng; i++) {
if (p(xs[i])) return Just(xs[i]);
}
return Nothing();
};

// findIndices(matching([2, 3]), [1, 2, 3, 1, 2, 3])
//-> {2, 5}

// findIndices :: (a -> Bool) -> [a] -> [Int]
// findIndices :: (String -> Bool) -> String -> [Int]
const findIndices = (p, xs) =>
concatMap((x, i) => p(x, i, xs) ? (
[i]
) : [], xs);

// fmapMay (<$>) :: (a -> b) -> Maybe a -> Maybe b
const fmapMay = (f, mb) =>
mb.Nothing ? (
mb
) : Just(f(mb.Just));

// foldl :: (a -> b -> a) -> a -> [b] -> a
const foldl = (f, a, xs) => xs.reduce(f, a);

// gcd :: Int -> Int -> Int
const gcd = (x, y) => {
const
_gcd = (a, b) => (0 === b ? a : _gcd(b, a % b)),
abs = Math.abs;
return _gcd(abs(x), abs(y));
};

// isChar :: a -> Bool
const isChar = x =>
('string' === typeof x) && (1 === x.length);

// iterate :: (a -> a) -> a -> Gen [a]
function* iterate(f, x) {
let v = x;
while (true) {
yield(v);
v = f(v);
}
}

// map :: (a -> b) -> [a] -> [b]
const map = (f, xs) => xs.map(f);

// mapMaybeGen :: (a -> Maybe b) -> Gen [a] -> [b]
function* mapMaybeGen(mf, gen) {
let v = take(1, gen);
while (0 < v.length) {
let mb = mf(v[0]);
if (!mb.Nothing) yield mb.Just
v = take(1, gen);
}
}

// Returns a sequence-matching function for findIndices etc
// findIndices(matching([2, 3]), [1, 2, 3, 1, 2, 3])
// -> [1, 4]

// matching :: [a] -> (a -> Int -> [a] -> Bool)
const matching = pat => {
const
lng = pat.length,
bln = 0 < lng,
h = bln ? pat[0] : undefined;
return (x, i, src) =>
bln && h == x &&
eq(pat, src.slice(i, lng + i));
};

// ord :: Char -> Int
const ord = c => c.codePointAt(0);

// properFracRatio :: Ratio -> (Int, Ratio)
const properFracRatio = nd => {
const [q, r] = Array.from(quotRem(nd.n, nd.d));
return Tuple(q, ratio(r, nd.d));
};

// quot :: Int -> Int -> Int
const quot = (n, m) => Math.floor(n / m);

// quotRem :: Int -> Int -> (Int, Int)
const quotRem = (m, n) =>
Tuple(Math.floor(m / n), m % n);

// ratio :: Int -> Int -> Ratio Int
const ratio = (n, d) =>
0 !== d ? (() => {
const g = gcd(n, d);
return {
type: 'Ratio',
'n': quot(n, g), // numerator
'd': quot(d, g) // denominator
}
})() : undefined;

// read :: Read a => String -> a
const read = JSON.parse;

// showLog :: a -> IO ()
const showLog = (...args) =>
console.log(
args
.map(JSON.stringify)
.join(' -> ')
);

// snd :: (a, b) -> b
const snd = tpl => tpl[1];

// splitOn :: [a] -> [a] -> [[a]]
// splitOn :: String -> String -> [String]
const splitOn = (pat, src) =>
src.split(pat);

// succ :: Int -> Int
const succ = x =>
1 + x;

// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take = (n, xs) =>
xs.constructor.constructor.name !== 'GeneratorFunction' ? (
xs.slice(0, n)
) : [].concat.apply([], Array.from({
length: n
}, () => {
const x = xs.next();
return x.done ? [] : [x.value];
}));

// takeWhileGen :: (a -> Bool) -> Gen [a] -> [a]
const takeWhileGen = (p, xs) => {
const ys = [];
let
nxt = xs.next(),
v = nxt.value;
while (!nxt.done && p(v)) {
ys.push(v);
nxt = xs.next();
v = nxt.value
}
return ys;
};

// truncate :: Num -> Int
const truncate = x =>
'Ratio' === x.type ? (
properFracRatio(x)[0]
) : properFraction(x)[0];

// MAIN ---
return main();
})();</lang>
{{Out}}
<pre>"First fifteen steps:" -> [2,15,825,725,1925,2275,425,390,330,290,770,910,170,156,132]
"First five primes:" -> [1,2,3,5,7]</pre>


=={{header|Julia}}==
=={{header|Julia}}==