Skip to content

Apéndice C: Utilidades en Estilo Pointfree

En este apéndice encontrarás versiones pointfree de funciones clásicas de JavaScript descritas en el libro. Todas las siguientes funciones están disponibles en los ejercicios como parte del contexto global. Ten en cuenta que estas implementaciones pueden no ser las más rápidas ni eficientes; su único propósito es educativo.

Para obtener implementaciones más adecuadas para producción, consulta bibliotecas como ramda, lodash o folktale.

Nota: Estas funciones hacen referencia a las funciones curry (currificación) y compose (composición) definidas en el Apéndice A.

add

js
// add :: Number -> Number -> Number
const add = curry((a, b) => a + b);

append

js
// append :: String -> String -> String
const append = flip(concat);

chain

js
// chain :: Monad m => (a -> m b) -> m a -> m b
const chain = curry((fn, m) => m.chain(fn));

concat

js
// concat :: String -> String -> String
const concat = curry((a, b) => a.concat(b));

eq

js
// eq :: Eq a => a -> a -> Boolean
const eq = curry((a, b) => a === b);

filter

js
// filter :: (a -> Boolean) -> [a] -> [a]
const filter = curry((fn, xs) => xs.filter(fn));

flip

js
// flip :: (a -> b -> c) -> b -> a -> c
const flip = curry((fn, a, b) => fn(b, a));

forEach

js
// forEach :: (a -> ()) -> [a] -> ()
const forEach = curry((fn, xs) => xs.forEach(fn));
js
// head :: [a] -> a
const head = xs => xs[0];

intercalate

js
// intercalate :: String -> [String] -> String
const intercalate = curry((str, xs) => xs.join(str));

join

js
// join :: Monad m => m (m a) -> m a
const join = m => m.join();

last

js
// last :: [a] -> a
const last = xs => xs[xs.length - 1];

map

js
// map :: Functor f => (a -> b) -> f a -> f b
const map = curry((fn, f) => f.map(fn));

match

js
// match :: RegExp -> String -> Boolean
const match = curry((re, str) => re.test(str));

prop

js
// prop :: String -> Object -> a
const prop = curry((p, obj) => obj[p]);

reduce

js
// reduce :: (b -> a -> b) -> b -> [a] -> b
const reduce = curry((fn, zero, xs) => xs.reduce(fn, zero));

replace

js
// replace :: RegExp -> String -> String -> String
const replace = curry((re, rpl, str) => str.replace(re, rpl));

reverse

js
// reverse :: [a] -> [a]
const reverse = x => (Array.isArray(x) ? x.reverse() : x.split('').reverse().join(''));

safeHead

js
// safeHead :: [a] -> Maybe a
const safeHead = compose(Maybe.of, head);

safeLast

js
// safeLast :: [a] -> Maybe a
const safeLast = compose(Maybe.of, last);

safeProp

js
// safeProp :: String -> Object -> Maybe a
const safeProp = curry((p, obj) => compose(Maybe.of, prop(p))(obj));

sequence

js
// sequence :: (Applicative f, Traversable t) => (a -> f a) -> t (f a) -> f (t a)
const sequence = curry((of, f) => f.sequence(of));

sortBy

js
// sortBy :: Ord b => (a -> b) -> [a] -> [a]
const sortBy = curry((fn, xs) => xs.sort((a, b) => {
  if (fn(a) === fn(b)) {
    return 0;
  }

  return fn(a) > fn(b) ? 1 : -1;
}));

split

js
// split :: String -> String -> [String]
const split = curry((sep, str) => str.split(sep));

take

js
// take :: Number -> [a] -> [a]
const take = curry((n, xs) => xs.slice(0, n));

toLowerCase

js
// toLowerCase :: String -> String
const toLowerCase = s => s.toLowerCase();

toString

js
// toString :: a -> String
const toString = String;

toUpperCase

js
// toUpperCase :: String -> String
const toUpperCase = s => s.toUpperCase();

traverse

js
// traverse :: (Applicative f, Traversable t) => (a -> f a) -> (a -> f b) -> t a -> f (t b)
const traverse = curry((of, fn, f) => f.traverse(of, fn));

unsafePerformIO

js
// unsafePerformIO :: IO a -> a
const unsafePerformIO = io => io.unsafePerformIO();