MostlyAdequate / mostly-adequate-guide

Mostly adequate guide to FP (in javascript)
Other
23.44k stars 1.87k forks source link

Chapter 8 references 'find' function that is not present in the appendix #564

Open ktr opened 4 years ago

ktr commented 4 years ago

Chapter 8 has a section that references a find function:

// findParam :: String -> IO Maybe [String]
const findParam = key => map(compose(Maybe.of, find(compose(eq(key), head)), params), url);

But there does not appear to be a find function in the Appendix. I believe this may have referenced filter before (per issue #303) and there is a definition of find in there, so perhaps it just needs to be added to appendix?

Thanks for great book - enjoying very much so far!

KtorZ commented 4 years ago

perhaps it just needs to be added to appendix?

I think you're right :)

dotnetCarpenter commented 3 years ago

Assuming ECMAScript 2015 (ES6) the example works with the following implementation of find:

// find :: Pred a => a -> [b] -> b
const find = curry((fn, list) => list.find(fn))
dotnetCarpenter commented 3 years ago

Here is a find implementation that follows the code style of the other Pointfree Utilities given in appendix C:

// find :: (a -> Boolean) -> [a] -> a
const find = curry(function find(fn, xs) {
  assert(
    typeof fn === 'function' && Array.isArray(xs),
    typeMismatch('(a -> Boolean) -> [a] -> a', [getType(fn), getType(xs), getType(xs)].join(' -> '), 'find'),
  );

  return xs.find(fn);
});
dotnetCarpenter commented 3 years ago

Note, that the example does not currently work with the support.js file for the book.

Current example:

// url :: IO String
const url = new IO(() => window.location.href);

// toPairs :: String -> [[String]]
const toPairs = compose(map(split('=')), split('&'));

// params :: String -> [[String]]
const params = compose(toPairs, last, split('?'));

// findParam :: String -> IO Maybe [String]
const findParam = key => map(compose(Maybe.of, find(compose(eq(key), head)), params), url);

// -- Impure calling code ----------------------------------------------

// run it by calling $value()!
findParam('searchTerm').$value();
// Just(['searchTerm', 'wafflehouse'])

Changes needed for the example to work (assuming find implementation in support.js as mention in previous comment):

'use strict'

const {
  IO,
  compose,
  map,
  split,
  last,
  Maybe,
  find,
  eq,
  head,
} = require('../support')

const window = {}
window.location = {}
window.location.href = 'https://www.example.com/foo?bar=yes&searchTerm=wafflehouse&wedonot=care'

// url :: IO String
const url = new IO(() => window.location.href);

// toPairs :: String -> [[String]]
const toPairs = compose(map(split('=')), split('&'));

// params :: String -> [[String]]
const params = compose(toPairs, last, split('?'));

// findParam :: String -> IO Maybe [String]
const findParam = key => map(compose(Maybe.of, find(compose(eq(key), head)), params), url);

// -- Impure calling code ----------------------------------------------

// run it by calling .unsafePerformIO()!
// findParam('searchTerm').unsafePerformIO();
const result = findParam('searchTerm').unsafePerformIO();
console.log(result) // Just(['searchTerm', 'wafflehouse'])
dotnetCarpenter commented 3 years ago

Oh no. There is 2 support.js files. One that is actually used, in this repo and @mostly-adequate/support. None of them has find but one has replace and the one (in this repo) which is actually used in the exercises, does not.

What is the correct place to add missing functions? Is there any reason to have @mostly-adequate/support as a package?

This is confusing and also the reason for https://github.com/MostlyAdequate/mostly-adequate-guide/issues/506