Shoelace formula for polygonal area: Difference between revisions

→‎{{header|JavaScript}}: Added a JS draft.
(→‎{{header|JavaScript}}: Added a JS draft.)
Line 654:
<pre>Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)],
its area is 30.000000,</pre>
 
=={{header|JavaScript}}==
<lang javascript>(() => {
'use strict';
 
// shoelaceArea :: [(Float, Float)] -> Float
const shoeLaceArea = vertices => abs(
uncurry(subtract)(
foldl(
a => x => map(
b => a[int(b)] + x[0][int(b)] * x[1][int(!b)]
)([0, 1])
)([0, 0])(
ap(zip)(compose(tail, cycle))(
vertices
)
)
)
) / 2;
 
 
// ----------------------- TEST -----------------------
const main = () => {
const ps = [
[3, 4],
[5, 11],
[12, 8],
[9, 5],
[5, 6]
];
return unlines([
'Polygonal area by shoelace formula:',
JSON.stringify(ps) + ' -> ' + shoeLaceArea(ps)
]);
};
 
 
// ---------------- GENERIC FUNCTIONS -----------------
 
// abs :: Num -> Num
const abs =
// Absolute value of a given number - without the sign.
Math.abs;
 
 
// ap :: (a -> b -> c) -> (a -> b) -> a -> c
const ap = f =>
// Applicative instance for functions.
// f(x) applied to g(x).
g => x => f(x)(
g(x)
);
 
 
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
fs.reduce(
(f, g) => x => f(g(x)),
x => x
);
 
 
// cycle :: [a] -> Generator [a]
function* cycle(xs) {
const lng = xs.length;
let i = 0;
while (true) {
yield(xs[i])
i = (1 + i) % lng;
}
}
 
// foldl :: (a -> b -> a) -> a -> [b] -> a
const foldl = f =>
a => xs => xs.reduce((x, y) => f(x)(y), a);
 
 
// int :: Bool -> Int
const int = bln =>
bln ? (
1
) : 0;
 
// length :: [a] -> Int
const length = xs =>
// 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
(Array.isArray(xs) || 'string' === typeof xs) ? (
xs.length
) : Infinity;
 
 
// map :: (a -> b) -> [a] -> [b]
const map = f =>
// The list obtained by applying f
// to each element of xs.
// (The image of xs under f).
xs => (
Array.isArray(xs) ? (
xs
) : xs.split('')
).map(f);
 
 
// subtract :: Num -> Num -> Num
const subtract = x =>
y => y - x;
 
 
// tail :: [a] -> [a]
const tail = xs =>
// A new list consisting of all
// items of xs except the first.
'GeneratorFunction' !== xs.constructor.constructor.name ? (
0 < xs.length ? xs.slice(1) : []
) : (take(1)(xs), xs);
 
 
// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take = n =>
// The first n elements of a list,
// string of characters, or stream.
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];
}));
 
 
// uncurry :: (a -> b -> c) -> ((a, b) -> c)
const uncurry = f =>
// A function over a pair, derived
// from a curried function.
function() {
const
args = arguments,
xy = Boolean(args.length % 2) ? (
args[0]
) : args;
return f(xy[0])(xy[1]);
};
 
 
// 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');
 
 
// zip :: [a] -> [b] -> [(a, b)]
const zip = xs =>
// Use of `take` and `length` here allows for zipping with non-finite
// lists - i.e. generators like cycle, repeat, iterate.
ys => {
const
lng = Math.min(length(xs), length(ys)),
vs = take(lng)(ys);
return take(lng)(xs).map(
(x, i) => [x, vs[i]]
);
};
 
// MAIN ---
return main();
})();</lang>
{{Out}}
<pre>Polygonal area by shoelace formula:
[[3,4],[5,11],[12,8],[9,5],[5,6]] -> 30</pre>
 
=={{header|Julia}}==
9,655

edits