Matrix multiplication: Difference between revisions

Content added Content deleted
(→‎JS ES6: Adjusted primitives, tidied.)
Line 3,756: Line 3,756:
===ES6===
===ES6===
<lang JavaScript>((() => {
<lang JavaScript>((() => {
'use strict';
"use strict";


// matrixMultiply :: Num a => [[a]] -> [[a]] -> [[a]]
// matrixMultiply :: Num a => [[a]] -> [[a]] -> [[a]]
Line 3,762: Line 3,762:
b => {
b => {
const cols = transpose(b);
const cols = transpose(b);

return map(
return a.map(
compose(
compose(
flip(map)(cols),
f => cols.map(f),
dotProduct
dotProduct
)
)
)(a);
);
};
};


Line 3,774: Line 3,775:
compose(sum, zipWith(mul)(xs));
compose(sum, zipWith(mul)(xs));



// ----------------------- TEST ------------------------
// ---------------------- TEST -----------------------
const main = () =>
const main = () =>
JSON.stringify(matrixMultiply(
JSON.stringify(matrixMultiply(
Line 3,788: Line 3,790:
]));
]));



// ---------------------- GENERIC ----------------------
// --------------------- GENERIC ---------------------


// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
const compose = (...fs) =>
const compose = (...fs) =>
// A function defined by the right-to-left
// composition of all the functions in fs.
fs.reduce(
fs.reduce(
(f, g) => x => f(g(x)),
(f, g) => x => f(g(x)),
Line 3,797: Line 3,802:
);
);


// flip :: (a -> b -> c) -> b -> a -> c
const flip = f =>
x => y => f(y)(x);

// 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 => xs.map(f);


// mul :: Num a => a -> a -> a
// mul :: Num a => a -> a -> a
const mul = a =>
const mul = a =>
b => a * b;
b => a * b;



// sum :: (Num a) => [a] -> a
// sum :: (Num a) => [a] -> a
Line 3,826: Line 3,812:
xs.reduce((a, x) => a + x, 0);
xs.reduce((a, x) => a + x, 0);


// take :: Int -> [a] -> [a]
// take :: Int -> String -> String
const take = n =>
// The first n elements of a list,
// string of characters, or stream.
xs => xs.slice(0, n);


// transpose :: [[a]] -> [[a]]
// transpose :: [[a]] -> [[a]]
Line 3,837: Line 3,817:
// The columns of the input transposed
// The columns of the input transposed
// into new rows.
// into new rows.
// Assumes input rows of even length.
// Simpler version of transpose, assuming input
0 < rows.length ? rows[0].map(
// rows of even length.
(x, i) => rows.flatMap(
Boolean(rows.length) ? rows[0].map(
x => x[i]
(_, i) => rows.flatMap(
v => v[i]
)
)
) : [];
) : [];



// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
Line 3,849: Line 3,831:
// custom function, rather than with the
// custom function, rather than with the
// default tuple constructor.
// default tuple constructor.
xs => ys => {
xs => ys => xs.map(
const
(x, i) => f(x)(ys[i])
).slice(
lng = Math.min(length(xs), length(ys)),
vs = take(lng)(ys);
0, Math.min(xs.length, ys.length)
return take(lng)(xs)
);
.map((x, i) => f(x)(vs[i]));
};


// MAIN ---
// MAIN ---